@tambo-ai/react 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) hide show
  1. package/README.md +1 -1
  2. package/dist/context-helpers/current-interactables-context-helper.d.ts +16 -2
  3. package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  4. package/dist/context-helpers/current-interactables-context-helper.js.map +1 -1
  5. package/dist/context-helpers/current-interactables-context-helper.test.d.ts +2 -0
  6. package/dist/context-helpers/current-interactables-context-helper.test.d.ts.map +1 -0
  7. package/dist/context-helpers/current-interactables-context-helper.test.js +70 -0
  8. package/dist/context-helpers/current-interactables-context-helper.test.js.map +1 -0
  9. package/dist/mcp/elicitation.d.ts +3 -37
  10. package/dist/mcp/elicitation.d.ts.map +1 -1
  11. package/dist/mcp/elicitation.js +7 -24
  12. package/dist/mcp/elicitation.js.map +1 -1
  13. package/dist/mcp/index.d.ts +4 -4
  14. package/dist/mcp/index.d.ts.map +1 -1
  15. package/dist/mcp/index.js +2 -2
  16. package/dist/mcp/index.js.map +1 -1
  17. package/dist/mcp/mcp-client.test.js +17 -17
  18. package/dist/mcp/mcp-client.test.js.map +1 -1
  19. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  20. package/dist/mcp/mcp-hooks.js +8 -5
  21. package/dist/mcp/mcp-hooks.js.map +1 -1
  22. package/dist/mcp/mcp-hooks.test.js +30 -29
  23. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  24. package/dist/mcp/tambo-mcp-provider.d.ts +6 -9
  25. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  26. package/dist/mcp/tambo-mcp-provider.js +9 -13
  27. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  28. package/dist/mcp/tambo-mcp-provider.test.js +26 -25
  29. package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
  30. package/dist/mcp/use-mcp-servers.test.js +2 -1
  31. package/dist/mcp/use-mcp-servers.test.js.map +1 -1
  32. package/dist/model/component-metadata.d.ts +7 -372
  33. package/dist/model/component-metadata.d.ts.map +1 -1
  34. package/dist/model/component-metadata.js.map +1 -1
  35. package/dist/model/validate-input.test.d.ts +2 -0
  36. package/dist/model/validate-input.test.d.ts.map +1 -0
  37. package/dist/model/validate-input.test.js +38 -0
  38. package/dist/model/validate-input.test.js.map +1 -0
  39. package/dist/providers/tambo-interactable-provider.d.ts +7 -7
  40. package/dist/providers/tambo-registry-provider.d.ts +1 -1
  41. package/dist/providers/tambo-registry-provider.d.ts.map +1 -1
  42. package/dist/providers/tambo-registry-provider.js.map +1 -1
  43. package/dist/providers/tambo-registry-schema-compat.test.js +4 -4
  44. package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -1
  45. package/dist/schema/index.d.ts +2 -4
  46. package/dist/schema/index.d.ts.map +1 -1
  47. package/dist/schema/index.js +9 -11
  48. package/dist/schema/index.js.map +1 -1
  49. package/dist/schema/json-schema.d.ts +1 -17
  50. package/dist/schema/json-schema.d.ts.map +1 -1
  51. package/dist/schema/json-schema.js +5 -69
  52. package/dist/schema/json-schema.js.map +1 -1
  53. package/dist/schema/schema.test.js +24 -25
  54. package/dist/schema/schema.test.js.map +1 -1
  55. package/dist/schema/standard-schema.test.js +25 -25
  56. package/dist/schema/standard-schema.test.js.map +1 -1
  57. package/dist/schema/validate.test.js +33 -33
  58. package/dist/schema/validate.test.js.map +1 -1
  59. package/dist/testing/tools.d.ts +4 -4
  60. package/dist/testing/tools.test.d.ts +2 -0
  61. package/dist/testing/tools.test.d.ts.map +1 -0
  62. package/dist/testing/tools.test.js +60 -0
  63. package/dist/testing/tools.test.js.map +1 -0
  64. package/dist/util/mcp-server-utils.d.ts +1 -1
  65. package/dist/util/mcp-server-utils.d.ts.map +1 -1
  66. package/dist/util/mcp-server-utils.js +4 -4
  67. package/dist/util/mcp-server-utils.js.map +1 -1
  68. package/dist/util/mcp-server-utils.test.js +27 -27
  69. package/dist/util/mcp-server-utils.test.js.map +1 -1
  70. package/dist/util/registry.js +1 -1
  71. package/dist/util/registry.js.map +1 -1
  72. package/dist/util/resource-content-resolver.js +5 -5
  73. package/dist/util/resource-content-resolver.js.map +1 -1
  74. package/dist/util/resource-content-resolver.test.js +6 -6
  75. package/dist/util/resource-content-resolver.test.js.map +1 -1
  76. package/dist/util/tool-caller.test.d.ts +2 -0
  77. package/dist/util/tool-caller.test.d.ts.map +1 -0
  78. package/dist/util/tool-caller.test.js +71 -0
  79. package/dist/util/tool-caller.test.js.map +1 -0
  80. package/dist/v1/__tests__/v1-interactables.test.js +1 -0
  81. package/dist/v1/__tests__/v1-interactables.test.js.map +1 -1
  82. package/dist/v1/hooks/use-tambo-v1-auth-state.d.ts +1 -1
  83. package/dist/v1/hooks/use-tambo-v1-auth-state.d.ts.map +1 -1
  84. package/dist/v1/hooks/use-tambo-v1-auth-state.js.map +1 -1
  85. package/dist/v1/hooks/use-tambo-v1-component-state.js +2 -2
  86. package/dist/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  87. package/dist/v1/hooks/use-tambo-v1-component-state.test.js +1 -1
  88. package/dist/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  89. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +1 -1
  90. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  91. package/dist/v1/hooks/use-tambo-v1-send-message.js +17 -17
  92. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  93. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +1 -1
  94. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  95. package/dist/v1/hooks/use-tambo-v1-stream-status.js +2 -2
  96. package/dist/v1/hooks/use-tambo-v1-stream-status.js.map +1 -1
  97. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js +9 -5
  98. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -1
  99. package/dist/v1/hooks/use-tambo-v1-suggestions.js +2 -2
  100. package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
  101. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +104 -0
  102. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  103. package/dist/v1/hooks/use-tambo-v1.d.ts +7 -6
  104. package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  105. package/dist/v1/hooks/use-tambo-v1.js +2 -2
  106. package/dist/v1/hooks/use-tambo-v1.js.map +1 -1
  107. package/dist/v1/hooks/use-tambo-v1.test.js +23 -23
  108. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
  109. package/dist/v1/index.d.ts +6 -6
  110. package/dist/v1/index.d.ts.map +1 -1
  111. package/dist/v1/index.js +2 -2
  112. package/dist/v1/index.js.map +1 -1
  113. package/dist/v1/providers/tambo-v1-provider.d.ts +2 -1
  114. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  115. package/dist/v1/providers/tambo-v1-provider.js +2 -0
  116. package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
  117. package/dist/v1/providers/tambo-v1-stream-context.d.ts +2 -2
  118. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  119. package/dist/v1/providers/tambo-v1-stream-context.js +9 -9
  120. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
  121. package/dist/v1/providers/tambo-v1-stream-context.test.js +35 -0
  122. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  123. package/dist/v1/providers/tambo-v1-stub-provider.d.ts +1 -1
  124. package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  125. package/dist/v1/providers/tambo-v1-stub-provider.js +1 -1
  126. package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  127. package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
  128. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +1 -1
  129. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  130. package/dist/v1/providers/tambo-v1-thread-input-provider.js +33 -17
  131. package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  132. package/dist/v1/types/event.test.js +13 -13
  133. package/dist/v1/types/event.test.js.map +1 -1
  134. package/dist/v1/types/message.d.ts +12 -109
  135. package/dist/v1/types/message.d.ts.map +1 -1
  136. package/dist/v1/types/message.js +0 -7
  137. package/dist/v1/types/message.js.map +1 -1
  138. package/dist/v1/utils/event-accumulator.test.js +183 -184
  139. package/dist/v1/utils/event-accumulator.test.js.map +1 -1
  140. package/dist/v1/utils/json-patch.test.js +4 -4
  141. package/dist/v1/utils/json-patch.test.js.map +1 -1
  142. package/dist/v1/utils/keyed-throttle.test.js +12 -12
  143. package/dist/v1/utils/keyed-throttle.test.js.map +1 -1
  144. package/dist/v1/utils/registry-conversion.test.js +13 -13
  145. package/dist/v1/utils/registry-conversion.test.js.map +1 -1
  146. package/dist/v1/utils/stream-handler.test.js +5 -5
  147. package/dist/v1/utils/stream-handler.test.js.map +1 -1
  148. package/dist/v1/utils/tool-call-tracker.test.js +15 -9
  149. package/dist/v1/utils/tool-call-tracker.test.js.map +1 -1
  150. package/dist/v1/utils/tool-executor.test.js +25 -26
  151. package/dist/v1/utils/tool-executor.test.js.map +1 -1
  152. package/dist/v1/utils/unstrictify.test.js +16 -16
  153. package/dist/v1/utils/unstrictify.test.js.map +1 -1
  154. package/esm/context-helpers/current-interactables-context-helper.d.ts +16 -2
  155. package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  156. package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
  157. package/esm/context-helpers/current-interactables-context-helper.test.d.ts +2 -0
  158. package/esm/context-helpers/current-interactables-context-helper.test.d.ts.map +1 -0
  159. package/esm/context-helpers/current-interactables-context-helper.test.js +68 -0
  160. package/esm/context-helpers/current-interactables-context-helper.test.js.map +1 -0
  161. package/esm/mcp/elicitation.d.ts +3 -37
  162. package/esm/mcp/elicitation.d.ts.map +1 -1
  163. package/esm/mcp/elicitation.js +4 -24
  164. package/esm/mcp/elicitation.js.map +1 -1
  165. package/esm/mcp/index.d.ts +4 -4
  166. package/esm/mcp/index.d.ts.map +1 -1
  167. package/esm/mcp/index.js +1 -1
  168. package/esm/mcp/index.js.map +1 -1
  169. package/esm/mcp/mcp-client.test.js +1 -1
  170. package/esm/mcp/mcp-client.test.js.map +1 -1
  171. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  172. package/esm/mcp/mcp-hooks.js +4 -1
  173. package/esm/mcp/mcp-hooks.js.map +1 -1
  174. package/esm/mcp/mcp-hooks.test.js +3 -2
  175. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  176. package/esm/mcp/tambo-mcp-provider.d.ts +6 -9
  177. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  178. package/esm/mcp/tambo-mcp-provider.js +4 -8
  179. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  180. package/esm/mcp/tambo-mcp-provider.test.js +3 -2
  181. package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
  182. package/esm/mcp/use-mcp-servers.test.js +2 -1
  183. package/esm/mcp/use-mcp-servers.test.js.map +1 -1
  184. package/esm/model/component-metadata.d.ts +7 -372
  185. package/esm/model/component-metadata.d.ts.map +1 -1
  186. package/esm/model/component-metadata.js.map +1 -1
  187. package/esm/model/validate-input.test.d.ts +2 -0
  188. package/esm/model/validate-input.test.d.ts.map +1 -0
  189. package/esm/model/validate-input.test.js +36 -0
  190. package/esm/model/validate-input.test.js.map +1 -0
  191. package/esm/providers/tambo-interactable-provider.d.ts +7 -7
  192. package/esm/providers/tambo-registry-provider.d.ts +1 -1
  193. package/esm/providers/tambo-registry-provider.d.ts.map +1 -1
  194. package/esm/providers/tambo-registry-provider.js.map +1 -1
  195. package/esm/providers/tambo-registry-schema-compat.test.js +4 -4
  196. package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -1
  197. package/esm/schema/index.d.ts +2 -4
  198. package/esm/schema/index.d.ts.map +1 -1
  199. package/esm/schema/index.js +2 -4
  200. package/esm/schema/index.js.map +1 -1
  201. package/esm/schema/json-schema.d.ts +1 -17
  202. package/esm/schema/json-schema.d.ts.map +1 -1
  203. package/esm/schema/json-schema.js +2 -67
  204. package/esm/schema/json-schema.js.map +1 -1
  205. package/esm/schema/schema.test.js +1 -2
  206. package/esm/schema/schema.test.js.map +1 -1
  207. package/esm/schema/standard-schema.test.js +1 -1
  208. package/esm/schema/standard-schema.test.js.map +1 -1
  209. package/esm/schema/validate.test.js +1 -1
  210. package/esm/schema/validate.test.js.map +1 -1
  211. package/esm/testing/tools.d.ts +4 -4
  212. package/esm/testing/tools.test.d.ts +2 -0
  213. package/esm/testing/tools.test.d.ts.map +1 -0
  214. package/esm/testing/tools.test.js +58 -0
  215. package/esm/testing/tools.test.js.map +1 -0
  216. package/esm/util/mcp-server-utils.d.ts +1 -1
  217. package/esm/util/mcp-server-utils.d.ts.map +1 -1
  218. package/esm/util/mcp-server-utils.js +1 -1
  219. package/esm/util/mcp-server-utils.js.map +1 -1
  220. package/esm/util/mcp-server-utils.test.js +1 -1
  221. package/esm/util/mcp-server-utils.test.js.map +1 -1
  222. package/esm/util/registry.js +1 -1
  223. package/esm/util/registry.js.map +1 -1
  224. package/esm/util/resource-content-resolver.js +1 -1
  225. package/esm/util/resource-content-resolver.js.map +1 -1
  226. package/esm/util/resource-content-resolver.test.js +2 -2
  227. package/esm/util/resource-content-resolver.test.js.map +1 -1
  228. package/esm/util/tool-caller.test.d.ts +2 -0
  229. package/esm/util/tool-caller.test.d.ts.map +1 -0
  230. package/esm/util/tool-caller.test.js +69 -0
  231. package/esm/util/tool-caller.test.js.map +1 -0
  232. package/esm/v1/__tests__/v1-interactables.test.js +1 -0
  233. package/esm/v1/__tests__/v1-interactables.test.js.map +1 -1
  234. package/esm/v1/hooks/use-tambo-v1-auth-state.d.ts +1 -1
  235. package/esm/v1/hooks/use-tambo-v1-auth-state.d.ts.map +1 -1
  236. package/esm/v1/hooks/use-tambo-v1-auth-state.js.map +1 -1
  237. package/esm/v1/hooks/use-tambo-v1-component-state.js +1 -1
  238. package/esm/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  239. package/esm/v1/hooks/use-tambo-v1-component-state.test.js +1 -1
  240. package/esm/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  241. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +1 -1
  242. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  243. package/esm/v1/hooks/use-tambo-v1-send-message.js +6 -6
  244. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  245. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +1 -1
  246. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  247. package/esm/v1/hooks/use-tambo-v1-stream-status.js +1 -1
  248. package/esm/v1/hooks/use-tambo-v1-stream-status.js.map +1 -1
  249. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js +9 -5
  250. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -1
  251. package/esm/v1/hooks/use-tambo-v1-suggestions.js +1 -1
  252. package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
  253. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +104 -0
  254. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  255. package/esm/v1/hooks/use-tambo-v1.d.ts +7 -6
  256. package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  257. package/esm/v1/hooks/use-tambo-v1.js +1 -1
  258. package/esm/v1/hooks/use-tambo-v1.js.map +1 -1
  259. package/esm/v1/hooks/use-tambo-v1.test.js +22 -22
  260. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
  261. package/esm/v1/index.d.ts +6 -6
  262. package/esm/v1/index.d.ts.map +1 -1
  263. package/esm/v1/index.js +1 -1
  264. package/esm/v1/index.js.map +1 -1
  265. package/esm/v1/providers/tambo-v1-provider.d.ts +2 -1
  266. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  267. package/esm/v1/providers/tambo-v1-provider.js +2 -0
  268. package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
  269. package/esm/v1/providers/tambo-v1-stream-context.d.ts +2 -2
  270. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  271. package/esm/v1/providers/tambo-v1-stream-context.js +1 -1
  272. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
  273. package/esm/v1/providers/tambo-v1-stream-context.test.js +35 -0
  274. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  275. package/esm/v1/providers/tambo-v1-stub-provider.d.ts +1 -1
  276. package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  277. package/esm/v1/providers/tambo-v1-stub-provider.js +1 -1
  278. package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  279. package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
  280. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +1 -1
  281. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  282. package/esm/v1/providers/tambo-v1-thread-input-provider.js +32 -16
  283. package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  284. package/esm/v1/types/event.test.js +1 -1
  285. package/esm/v1/types/event.test.js.map +1 -1
  286. package/esm/v1/types/message.d.ts +12 -109
  287. package/esm/v1/types/message.d.ts.map +1 -1
  288. package/esm/v1/types/message.js +0 -7
  289. package/esm/v1/types/message.js.map +1 -1
  290. package/esm/v1/utils/event-accumulator.test.js +2 -3
  291. package/esm/v1/utils/event-accumulator.test.js.map +1 -1
  292. package/esm/v1/utils/json-patch.test.js +1 -1
  293. package/esm/v1/utils/json-patch.test.js.map +1 -1
  294. package/esm/v1/utils/keyed-throttle.test.js +1 -1
  295. package/esm/v1/utils/keyed-throttle.test.js.map +1 -1
  296. package/esm/v1/utils/registry-conversion.test.js +1 -1
  297. package/esm/v1/utils/registry-conversion.test.js.map +1 -1
  298. package/esm/v1/utils/stream-handler.test.js +1 -1
  299. package/esm/v1/utils/stream-handler.test.js.map +1 -1
  300. package/esm/v1/utils/tool-call-tracker.test.js +9 -3
  301. package/esm/v1/utils/tool-call-tracker.test.js.map +1 -1
  302. package/esm/v1/utils/tool-executor.test.js +1 -2
  303. package/esm/v1/utils/tool-executor.test.js.map +1 -1
  304. package/esm/v1/utils/unstrictify.test.js +1 -1
  305. package/esm/v1/utils/unstrictify.test.js.map +1 -1
  306. package/package.json +12 -15
  307. package/dist/mcp/mcp-client.d.ts +0 -185
  308. package/dist/mcp/mcp-client.d.ts.map +0 -1
  309. package/dist/mcp/mcp-client.js +0 -219
  310. package/dist/mcp/mcp-client.js.map +0 -1
  311. package/dist/mcp/mcp-constants.d.ts +0 -19
  312. package/dist/mcp/mcp-constants.d.ts.map +0 -1
  313. package/dist/mcp/mcp-constants.js +0 -21
  314. package/dist/mcp/mcp-constants.js.map +0 -1
  315. package/dist/model/mcp-server-info.d.ts +0 -76
  316. package/dist/model/mcp-server-info.d.ts.map +0 -1
  317. package/dist/model/mcp-server-info.js +0 -29
  318. package/dist/model/mcp-server-info.js.map +0 -1
  319. package/dist/schema/schema.d.ts +0 -49
  320. package/dist/schema/schema.d.ts.map +0 -1
  321. package/dist/schema/schema.js +0 -129
  322. package/dist/schema/schema.js.map +0 -1
  323. package/dist/schema/standard-schema.d.ts +0 -22
  324. package/dist/schema/standard-schema.d.ts.map +0 -1
  325. package/dist/schema/standard-schema.js +0 -42
  326. package/dist/schema/standard-schema.js.map +0 -1
  327. package/dist/schema/validate.d.ts +0 -14
  328. package/dist/schema/validate.d.ts.map +0 -1
  329. package/dist/schema/validate.js +0 -148
  330. package/dist/schema/validate.js.map +0 -1
  331. package/dist/v1/types/auth.d.ts +0 -24
  332. package/dist/v1/types/auth.d.ts.map +0 -1
  333. package/dist/v1/types/auth.js +0 -3
  334. package/dist/v1/types/auth.js.map +0 -1
  335. package/dist/v1/types/event.d.ts +0 -89
  336. package/dist/v1/types/event.d.ts.map +0 -1
  337. package/dist/v1/types/event.js +0 -57
  338. package/dist/v1/types/event.js.map +0 -1
  339. package/dist/v1/types/thread.d.ts +0 -58
  340. package/dist/v1/types/thread.d.ts.map +0 -1
  341. package/dist/v1/types/thread.js +0 -9
  342. package/dist/v1/types/thread.js.map +0 -1
  343. package/dist/v1/types/tool-choice.d.ts +0 -8
  344. package/dist/v1/types/tool-choice.d.ts.map +0 -1
  345. package/dist/v1/types/tool-choice.js +0 -3
  346. package/dist/v1/types/tool-choice.js.map +0 -1
  347. package/dist/v1/utils/event-accumulator.d.ts +0 -165
  348. package/dist/v1/utils/event-accumulator.d.ts.map +0 -1
  349. package/dist/v1/utils/event-accumulator.js +0 -1277
  350. package/dist/v1/utils/event-accumulator.js.map +0 -1
  351. package/dist/v1/utils/json-patch.d.ts +0 -18
  352. package/dist/v1/utils/json-patch.d.ts.map +0 -1
  353. package/dist/v1/utils/json-patch.js +0 -35
  354. package/dist/v1/utils/json-patch.js.map +0 -1
  355. package/dist/v1/utils/keyed-throttle.d.ts +0 -42
  356. package/dist/v1/utils/keyed-throttle.d.ts.map +0 -1
  357. package/dist/v1/utils/keyed-throttle.js +0 -86
  358. package/dist/v1/utils/keyed-throttle.js.map +0 -1
  359. package/dist/v1/utils/registry-conversion.d.ts +0 -53
  360. package/dist/v1/utils/registry-conversion.d.ts.map +0 -1
  361. package/dist/v1/utils/registry-conversion.js +0 -115
  362. package/dist/v1/utils/registry-conversion.js.map +0 -1
  363. package/dist/v1/utils/stream-handler.d.ts +0 -45
  364. package/dist/v1/utils/stream-handler.d.ts.map +0 -1
  365. package/dist/v1/utils/stream-handler.js +0 -47
  366. package/dist/v1/utils/stream-handler.js.map +0 -1
  367. package/dist/v1/utils/thread-utils.d.ts +0 -16
  368. package/dist/v1/utils/thread-utils.d.ts.map +0 -1
  369. package/dist/v1/utils/thread-utils.js +0 -34
  370. package/dist/v1/utils/thread-utils.js.map +0 -1
  371. package/dist/v1/utils/tool-call-tracker.d.ts +0 -73
  372. package/dist/v1/utils/tool-call-tracker.d.ts.map +0 -1
  373. package/dist/v1/utils/tool-call-tracker.js +0 -180
  374. package/dist/v1/utils/tool-call-tracker.js.map +0 -1
  375. package/dist/v1/utils/tool-executor.d.ts +0 -67
  376. package/dist/v1/utils/tool-executor.d.ts.map +0 -1
  377. package/dist/v1/utils/tool-executor.js +0 -160
  378. package/dist/v1/utils/tool-executor.js.map +0 -1
  379. package/dist/v1/utils/unstrictify.d.ts +0 -32
  380. package/dist/v1/utils/unstrictify.d.ts.map +0 -1
  381. package/dist/v1/utils/unstrictify.js +0 -159
  382. package/dist/v1/utils/unstrictify.js.map +0 -1
  383. package/esm/mcp/mcp-client.d.ts +0 -185
  384. package/esm/mcp/mcp-client.d.ts.map +0 -1
  385. package/esm/mcp/mcp-client.js +0 -216
  386. package/esm/mcp/mcp-client.js.map +0 -1
  387. package/esm/mcp/mcp-constants.d.ts +0 -19
  388. package/esm/mcp/mcp-constants.d.ts.map +0 -1
  389. package/esm/mcp/mcp-constants.js +0 -18
  390. package/esm/mcp/mcp-constants.js.map +0 -1
  391. package/esm/model/mcp-server-info.d.ts +0 -76
  392. package/esm/model/mcp-server-info.d.ts.map +0 -1
  393. package/esm/model/mcp-server-info.js +0 -25
  394. package/esm/model/mcp-server-info.js.map +0 -1
  395. package/esm/schema/schema.d.ts +0 -49
  396. package/esm/schema/schema.d.ts.map +0 -1
  397. package/esm/schema/schema.js +0 -124
  398. package/esm/schema/schema.js.map +0 -1
  399. package/esm/schema/standard-schema.d.ts +0 -22
  400. package/esm/schema/standard-schema.d.ts.map +0 -1
  401. package/esm/schema/standard-schema.js +0 -39
  402. package/esm/schema/standard-schema.js.map +0 -1
  403. package/esm/schema/validate.d.ts +0 -14
  404. package/esm/schema/validate.d.ts.map +0 -1
  405. package/esm/schema/validate.js +0 -145
  406. package/esm/schema/validate.js.map +0 -1
  407. package/esm/v1/types/auth.d.ts +0 -24
  408. package/esm/v1/types/auth.d.ts.map +0 -1
  409. package/esm/v1/types/auth.js +0 -2
  410. package/esm/v1/types/auth.js.map +0 -1
  411. package/esm/v1/types/event.d.ts +0 -89
  412. package/esm/v1/types/event.d.ts.map +0 -1
  413. package/esm/v1/types/event.js +0 -53
  414. package/esm/v1/types/event.js.map +0 -1
  415. package/esm/v1/types/thread.d.ts +0 -58
  416. package/esm/v1/types/thread.d.ts.map +0 -1
  417. package/esm/v1/types/thread.js +0 -8
  418. package/esm/v1/types/thread.js.map +0 -1
  419. package/esm/v1/types/tool-choice.d.ts +0 -8
  420. package/esm/v1/types/tool-choice.d.ts.map +0 -1
  421. package/esm/v1/types/tool-choice.js +0 -2
  422. package/esm/v1/types/tool-choice.js.map +0 -1
  423. package/esm/v1/utils/event-accumulator.d.ts +0 -165
  424. package/esm/v1/utils/event-accumulator.d.ts.map +0 -1
  425. package/esm/v1/utils/event-accumulator.js +0 -1268
  426. package/esm/v1/utils/event-accumulator.js.map +0 -1
  427. package/esm/v1/utils/json-patch.d.ts +0 -18
  428. package/esm/v1/utils/json-patch.d.ts.map +0 -1
  429. package/esm/v1/utils/json-patch.js +0 -32
  430. package/esm/v1/utils/json-patch.js.map +0 -1
  431. package/esm/v1/utils/keyed-throttle.d.ts +0 -42
  432. package/esm/v1/utils/keyed-throttle.d.ts.map +0 -1
  433. package/esm/v1/utils/keyed-throttle.js +0 -83
  434. package/esm/v1/utils/keyed-throttle.js.map +0 -1
  435. package/esm/v1/utils/registry-conversion.d.ts +0 -53
  436. package/esm/v1/utils/registry-conversion.d.ts.map +0 -1
  437. package/esm/v1/utils/registry-conversion.js +0 -109
  438. package/esm/v1/utils/registry-conversion.js.map +0 -1
  439. package/esm/v1/utils/stream-handler.d.ts +0 -45
  440. package/esm/v1/utils/stream-handler.d.ts.map +0 -1
  441. package/esm/v1/utils/stream-handler.js +0 -44
  442. package/esm/v1/utils/stream-handler.js.map +0 -1
  443. package/esm/v1/utils/thread-utils.d.ts +0 -16
  444. package/esm/v1/utils/thread-utils.d.ts.map +0 -1
  445. package/esm/v1/utils/thread-utils.js +0 -31
  446. package/esm/v1/utils/thread-utils.js.map +0 -1
  447. package/esm/v1/utils/tool-call-tracker.d.ts +0 -73
  448. package/esm/v1/utils/tool-call-tracker.d.ts.map +0 -1
  449. package/esm/v1/utils/tool-call-tracker.js +0 -176
  450. package/esm/v1/utils/tool-call-tracker.js.map +0 -1
  451. package/esm/v1/utils/tool-executor.d.ts +0 -67
  452. package/esm/v1/utils/tool-executor.d.ts.map +0 -1
  453. package/esm/v1/utils/tool-executor.js +0 -154
  454. package/esm/v1/utils/tool-executor.js.map +0 -1
  455. package/esm/v1/utils/unstrictify.d.ts +0 -32
  456. package/esm/v1/utils/unstrictify.d.ts.map +0 -1
  457. package/esm/v1/utils/unstrictify.js +0 -155
  458. package/esm/v1/utils/unstrictify.js.map +0 -1
@@ -1,1268 +0,0 @@
1
- /**
2
- * Event Accumulation Logic for Streaming API
3
- *
4
- * Implements a reducer that transforms AG-UI event streams into React state.
5
- * Used with useReducer to accumulate events into thread state.
6
- */
7
- import { EventType } from "@ag-ui/core";
8
- import { asTamboCustomEvent, } from "../types/event.js";
9
- import { parse as parsePartialJson } from "partial-json";
10
- import { applyJsonPatch } from "./json-patch.js";
11
- import { unstrictifyToolCallParamsFromSchema } from "./unstrictify.js";
12
- /**
13
- * Error thrown when an unreachable case is reached in a switch statement.
14
- * This indicates a programming error where not all cases were handled.
15
- */
16
- export class UnreachableCaseError extends Error {
17
- constructor(value) {
18
- super(`Unreachable case: ${JSON.stringify(value)}`);
19
- this.name = "UnreachableCaseError";
20
- }
21
- }
22
- /**
23
- * Initial streaming state.
24
- */
25
- const initialStreamingState = {
26
- status: "idle",
27
- };
28
- /**
29
- * Create initial thread state for a new thread.
30
- * @param threadId - Unique thread identifier
31
- * @returns Initial thread state
32
- */
33
- export function createInitialThreadState(threadId) {
34
- const now = new Date().toISOString();
35
- return {
36
- thread: {
37
- id: threadId,
38
- messages: [],
39
- status: "idle",
40
- createdAt: now,
41
- updatedAt: now,
42
- lastRunCancelled: false,
43
- },
44
- streaming: initialStreamingState,
45
- accumulatingToolArgs: new Map(),
46
- };
47
- }
48
- /**
49
- * Placeholder thread ID used for new threads before they get a real ID from the server.
50
- * This allows optimistic UI updates (showing user messages immediately) before the
51
- * server responds with the actual thread ID.
52
- */
53
- export const PLACEHOLDER_THREAD_ID = "placeholder";
54
- /**
55
- * Check if a thread ID is a placeholder (not a real API thread ID).
56
- * @param threadId - Thread ID to check
57
- * @returns True if this is a placeholder thread ID
58
- */
59
- export function isPlaceholderThreadId(threadId) {
60
- return threadId === PLACEHOLDER_THREAD_ID;
61
- }
62
- /**
63
- * Create initial stream state with placeholder thread.
64
- * @returns Initial stream state
65
- */
66
- export function createInitialState() {
67
- return {
68
- threadMap: {
69
- [PLACEHOLDER_THREAD_ID]: createInitialThreadState(PLACEHOLDER_THREAD_ID),
70
- },
71
- currentThreadId: PLACEHOLDER_THREAD_ID,
72
- };
73
- }
74
- /**
75
- * Create initial stream state with placeholder thread seeded with initial messages.
76
- * The messages are converted from InputMessage format to TamboThreadMessage format
77
- * for immediate UI display before any API call.
78
- * @param initialMessages - Messages to seed the placeholder thread with
79
- * @returns Initial stream state with messages in the placeholder thread
80
- */
81
- export function createInitialStateWithMessages(initialMessages) {
82
- const placeholderState = createInitialThreadState(PLACEHOLDER_THREAD_ID);
83
- const messages = initialMessages.map((msg) => ({
84
- id: `initial_${crypto.randomUUID()}`,
85
- role: msg.role,
86
- content: msg.content.map((c) => {
87
- if (c.type === "text") {
88
- return { type: "text", text: c.text };
89
- }
90
- return c;
91
- }),
92
- }));
93
- return {
94
- threadMap: {
95
- [PLACEHOLDER_THREAD_ID]: {
96
- ...placeholderState,
97
- thread: {
98
- ...placeholderState.thread,
99
- messages,
100
- },
101
- },
102
- },
103
- currentThreadId: PLACEHOLDER_THREAD_ID,
104
- };
105
- }
106
- /**
107
- * Replace a message at a specific index immutably.
108
- * @param messages - Current messages array
109
- * @param index - Index of message to replace
110
- * @param updatedMessage - New message to insert
111
- * @returns New messages array with the message replaced
112
- */
113
- function updateMessageAtIndex(messages, index, updatedMessage) {
114
- return [
115
- ...messages.slice(0, index),
116
- updatedMessage,
117
- ...messages.slice(index + 1),
118
- ];
119
- }
120
- /**
121
- * Replace a content block at a specific index within a message's content immutably.
122
- * @param content - Current content array
123
- * @param index - Index of content to replace
124
- * @param updatedContent - New content to insert
125
- * @returns New content array with the content replaced
126
- */
127
- function updateContentAtIndex(content, index, updatedContent) {
128
- return [
129
- ...content.slice(0, index),
130
- updatedContent,
131
- ...content.slice(index + 1),
132
- ];
133
- }
134
- /**
135
- * Find a content block by ID across all messages, searching from most recent.
136
- *
137
- * TODO: This is O(n*m) where n = messages and m = content blocks per message.
138
- * For high-frequency streaming with many messages, consider maintaining an
139
- * index map of contentId -> {messageIndex, contentIndex} that gets updated
140
- * when content blocks are created.
141
- * @param messages - Messages to search
142
- * @param contentType - Type of content to find ("component" or "tool_use")
143
- * @param contentId - ID of the content block
144
- * @param eventName - Name of the event (for error messages)
145
- * @returns Location of the content block
146
- * @throws {Error} If content not found
147
- */
148
- function findContentById(messages, contentType, contentId, eventName) {
149
- for (let i = messages.length - 1; i >= 0; i--) {
150
- const idx = messages[i].content.findIndex((c) => c.type === contentType && c.id === contentId);
151
- if (idx !== -1) {
152
- return { messageIndex: i, contentIndex: idx };
153
- }
154
- }
155
- throw new Error(`${contentType} ${contentId} not found for ${eventName}`);
156
- }
157
- /**
158
- * Create updated thread state with new messages.
159
- * @param threadState - Current thread state
160
- * @param messages - New messages array
161
- * @returns Updated thread state
162
- */
163
- function updateThreadMessages(threadState, messages) {
164
- return {
165
- ...threadState,
166
- thread: {
167
- ...threadState.thread,
168
- messages,
169
- updatedAt: new Date().toISOString(),
170
- },
171
- };
172
- }
173
- /**
174
- * Stream reducer that accumulates events into thread state.
175
- *
176
- * This reducer handles all AG-UI events and Tambo custom events,
177
- * transforming them into immutable state updates per thread.
178
- * @param state - Current stream state
179
- * @param action - Action to process
180
- * @returns Updated stream state
181
- */
182
- export function streamReducer(state, action) {
183
- // Handle non-event actions first
184
- switch (action.type) {
185
- case "INIT_THREAD": {
186
- const { threadId, initialThread } = action;
187
- // Don't overwrite existing thread
188
- if (state.threadMap[threadId]) {
189
- return state;
190
- }
191
- const baseState = createInitialThreadState(threadId);
192
- const threadState = initialThread
193
- ? {
194
- ...baseState,
195
- thread: {
196
- ...baseState.thread,
197
- ...initialThread,
198
- id: threadId,
199
- },
200
- }
201
- : baseState;
202
- return {
203
- ...state,
204
- threadMap: {
205
- ...state.threadMap,
206
- [threadId]: threadState,
207
- },
208
- };
209
- }
210
- case "SET_CURRENT_THREAD": {
211
- return {
212
- ...state,
213
- currentThreadId: action.threadId,
214
- };
215
- }
216
- case "START_NEW_THREAD": {
217
- // Atomic action: initialize thread AND set as current in one reducer pass.
218
- // Always overwrites any existing thread state for this ID — the whole
219
- // point of START_NEW_THREAD is to reset and start fresh (e.g. the
220
- // placeholder thread must be wiped clean on every new conversation).
221
- const { threadId, initialThread } = action;
222
- const baseState = createInitialThreadState(threadId);
223
- const threadState = initialThread
224
- ? {
225
- ...baseState,
226
- thread: {
227
- ...baseState.thread,
228
- ...initialThread,
229
- id: threadId,
230
- },
231
- }
232
- : baseState;
233
- return {
234
- ...state,
235
- threadMap: {
236
- ...state.threadMap,
237
- [threadId]: threadState,
238
- },
239
- currentThreadId: threadId,
240
- };
241
- }
242
- case "LOAD_THREAD_MESSAGES": {
243
- return handleLoadThreadMessages(state, action);
244
- }
245
- case "SET_LAST_COMPLETED_RUN_ID": {
246
- const threadState = state.threadMap[action.threadId] ??
247
- createInitialThreadState(action.threadId);
248
- return {
249
- ...state,
250
- threadMap: {
251
- ...state.threadMap,
252
- [action.threadId]: {
253
- ...threadState,
254
- lastCompletedRunId: action.lastCompletedRunId,
255
- },
256
- },
257
- };
258
- }
259
- case "UPDATE_THREAD_NAME": {
260
- const threadState = state.threadMap[action.threadId];
261
- if (!threadState) {
262
- return state;
263
- }
264
- return {
265
- ...state,
266
- threadMap: {
267
- ...state.threadMap,
268
- [action.threadId]: {
269
- ...threadState,
270
- thread: {
271
- ...threadState.thread,
272
- name: action.name,
273
- },
274
- },
275
- },
276
- };
277
- }
278
- case "EVENT":
279
- // Fall through to event handling below
280
- break;
281
- }
282
- // Handle EVENT action
283
- const { event, threadId } = action;
284
- const effectiveThreadId = event.type === EventType.RUN_STARTED ? event.threadId : threadId;
285
- // Get the current thread state, auto-initializing if needed
286
- // Auto-initialization handles the case where events arrive before explicit thread init
287
- // (e.g., when creating a new thread and RUN_STARTED is the first event)
288
- let threadState = state.threadMap[effectiveThreadId];
289
- let updatedState = state;
290
- if (!threadState) {
291
- // Auto-initialize the thread to avoid dropping events
292
- threadState = createInitialThreadState(effectiveThreadId);
293
- updatedState = {
294
- ...state,
295
- threadMap: {
296
- ...state.threadMap,
297
- [effectiveThreadId]: threadState,
298
- },
299
- };
300
- }
301
- // Handle placeholder thread migration for RUN_STARTED events
302
- // When a new thread is created, messages may have been added to the placeholder thread
303
- // for immediate UI feedback. Now that we have the real threadId, migrate those messages.
304
- if (event.type === EventType.RUN_STARTED &&
305
- effectiveThreadId !== PLACEHOLDER_THREAD_ID) {
306
- const placeholderState = updatedState.threadMap[PLACEHOLDER_THREAD_ID];
307
- if (placeholderState?.thread.messages.length) {
308
- // Prepend placeholder thread messages to the real thread
309
- threadState = {
310
- ...threadState,
311
- thread: {
312
- ...threadState.thread,
313
- messages: [
314
- ...placeholderState.thread.messages,
315
- ...threadState.thread.messages,
316
- ],
317
- },
318
- };
319
- // Reset placeholder thread to empty state
320
- const resetPlaceholder = createInitialThreadState(PLACEHOLDER_THREAD_ID);
321
- updatedState = {
322
- ...updatedState,
323
- threadMap: {
324
- ...updatedState.threadMap,
325
- [PLACEHOLDER_THREAD_ID]: resetPlaceholder,
326
- [effectiveThreadId]: threadState,
327
- },
328
- // Only switch selection if the user is currently on the placeholder thread
329
- currentThreadId: isPlaceholderThreadId(updatedState.currentThreadId)
330
- ? effectiveThreadId
331
- : updatedState.currentThreadId,
332
- };
333
- }
334
- }
335
- // Process the event for this specific thread
336
- let updatedThreadState;
337
- // Switch on event.type - AGUIEvent is a discriminated union so TypeScript
338
- // automatically narrows the type in each case branch
339
- switch (event.type) {
340
- case EventType.RUN_STARTED:
341
- updatedThreadState = handleRunStarted(threadState, event);
342
- break;
343
- case EventType.RUN_FINISHED:
344
- updatedThreadState = handleRunFinished(threadState, event);
345
- break;
346
- case EventType.RUN_ERROR:
347
- updatedThreadState = handleRunError(threadState, event);
348
- break;
349
- case EventType.TEXT_MESSAGE_START:
350
- updatedThreadState = handleTextMessageStart(threadState, event);
351
- break;
352
- case EventType.TEXT_MESSAGE_CONTENT:
353
- updatedThreadState = handleTextMessageContent(threadState, event);
354
- break;
355
- case EventType.TEXT_MESSAGE_END:
356
- updatedThreadState = handleTextMessageEnd(threadState, event);
357
- break;
358
- case EventType.TOOL_CALL_START:
359
- updatedThreadState = handleToolCallStart(threadState, event);
360
- break;
361
- case EventType.TOOL_CALL_ARGS:
362
- updatedThreadState = handleToolCallArgs(threadState, event, action.parsedToolArgs, action.toolSchemas);
363
- break;
364
- case EventType.TOOL_CALL_END:
365
- updatedThreadState = handleToolCallEnd(threadState, event, action.toolSchemas);
366
- break;
367
- case EventType.TOOL_CALL_RESULT:
368
- updatedThreadState = handleToolCallResult(threadState, event);
369
- break;
370
- case EventType.CUSTOM:
371
- updatedThreadState = handleCustomEvent(threadState, event);
372
- break;
373
- case EventType.THINKING_TEXT_MESSAGE_START:
374
- updatedThreadState = handleThinkingTextMessageStart(threadState, event);
375
- break;
376
- case EventType.THINKING_TEXT_MESSAGE_CONTENT:
377
- updatedThreadState = handleThinkingTextMessageContent(threadState, event);
378
- break;
379
- case EventType.THINKING_TEXT_MESSAGE_END:
380
- updatedThreadState = handleThinkingTextMessageEnd(threadState, event);
381
- break;
382
- // Unsupported AG-UI event types - may be added in future phases
383
- case EventType.TEXT_MESSAGE_CHUNK:
384
- case EventType.TOOL_CALL_CHUNK:
385
- case EventType.THINKING_START:
386
- case EventType.THINKING_END:
387
- case EventType.STATE_SNAPSHOT:
388
- case EventType.STATE_DELTA:
389
- case EventType.MESSAGES_SNAPSHOT:
390
- case EventType.ACTIVITY_SNAPSHOT:
391
- case EventType.ACTIVITY_DELTA:
392
- case EventType.RAW:
393
- case EventType.STEP_STARTED:
394
- case EventType.STEP_FINISHED:
395
- // Log warning - these events are being ignored
396
- console.warn(`[StreamReducer] Received unsupported event type: ${event.type}. ` +
397
- `This event will be ignored.`);
398
- return updatedState;
399
- default: {
400
- // Exhaustiveness check: if a new event type is added to AGUIEvent
401
- // and not handled above, TypeScript will error here
402
- const _exhaustiveCheck = event;
403
- throw new UnreachableCaseError(_exhaustiveCheck);
404
- }
405
- }
406
- // Return updated state with modified thread
407
- return {
408
- ...updatedState,
409
- threadMap: {
410
- ...updatedState.threadMap,
411
- [effectiveThreadId]: updatedThreadState,
412
- },
413
- };
414
- }
415
- /**
416
- * Handle RUN_STARTED event.
417
- * @param threadState - Current thread state
418
- * @param event - Run started event
419
- * @returns Updated thread state
420
- */
421
- function handleRunStarted(threadState, event) {
422
- return {
423
- ...threadState,
424
- thread: {
425
- ...threadState.thread,
426
- status: "streaming",
427
- updatedAt: new Date().toISOString(),
428
- // Reset lastRunCancelled when a new run starts
429
- lastRunCancelled: false,
430
- },
431
- streaming: {
432
- status: "streaming",
433
- runId: event.runId,
434
- startTime: event.timestamp ?? Date.now(),
435
- },
436
- };
437
- }
438
- /**
439
- * Handle RUN_FINISHED event.
440
- * @param threadState - Current thread state
441
- * @param event - Run finished event containing the completed run's ID
442
- * @returns Updated thread state
443
- */
444
- function handleRunFinished(threadState, event) {
445
- return {
446
- ...threadState,
447
- lastCompletedRunId: event.runId ??
448
- threadState.streaming.runId ??
449
- threadState.lastCompletedRunId,
450
- thread: {
451
- ...threadState.thread,
452
- status: "idle",
453
- updatedAt: new Date().toISOString(),
454
- },
455
- streaming: {
456
- ...threadState.streaming,
457
- status: "idle",
458
- },
459
- };
460
- }
461
- /**
462
- * Handle RUN_ERROR event.
463
- * Sets lastRunCancelled if the error code is "CANCELLED".
464
- * @param threadState - Current thread state
465
- * @param event - Run error event
466
- * @returns Updated thread state
467
- */
468
- function handleRunError(threadState, event) {
469
- const isCancelled = event.code === "CANCELLED";
470
- return {
471
- ...threadState,
472
- thread: {
473
- ...threadState.thread,
474
- status: "idle",
475
- updatedAt: new Date().toISOString(),
476
- lastRunCancelled: isCancelled,
477
- },
478
- streaming: {
479
- ...threadState.streaming,
480
- status: "idle",
481
- error: isCancelled
482
- ? undefined
483
- : {
484
- message: event.message,
485
- code: event.code,
486
- },
487
- },
488
- };
489
- }
490
- /**
491
- * Handle TEXT_MESSAGE_START event.
492
- * Creates a new message or reuses an ephemeral reasoning message.
493
- * @param threadState - Current thread state
494
- * @param event - Text message start event
495
- * @returns Updated thread state
496
- */
497
- function handleTextMessageStart(threadState, event) {
498
- const isAssistant = event.role !== "user";
499
- const messages = threadState.thread.messages;
500
- // For assistant messages, check if there's an ephemeral message with reasoning
501
- // that we should merge into instead of creating a new message.
502
- if (isAssistant) {
503
- const ephemeralIndex = messages.findIndex((m) => m.role === "assistant" &&
504
- m.id.startsWith("ephemeral_") &&
505
- m.reasoning &&
506
- m.reasoning.length > 0);
507
- if (ephemeralIndex !== -1) {
508
- // Update the ephemeral message with the real ID
509
- const ephemeralMessage = messages[ephemeralIndex];
510
- const updatedMessages = [...messages];
511
- updatedMessages[ephemeralIndex] = {
512
- ...ephemeralMessage,
513
- id: event.messageId,
514
- };
515
- return {
516
- ...threadState,
517
- thread: {
518
- ...threadState.thread,
519
- messages: updatedMessages,
520
- updatedAt: new Date().toISOString(),
521
- },
522
- streaming: {
523
- ...threadState.streaming,
524
- messageId: event.messageId,
525
- },
526
- };
527
- }
528
- }
529
- // Check if a message with this ID already exists (e.g., created by
530
- // handleMessageParent). If so, just update streaming state to track it.
531
- const existingIndex = messages.findIndex((m) => m.id === event.messageId);
532
- if (existingIndex !== -1) {
533
- return {
534
- ...threadState,
535
- thread: {
536
- ...threadState.thread,
537
- updatedAt: new Date().toISOString(),
538
- },
539
- streaming: {
540
- ...threadState.streaming,
541
- messageId: event.messageId,
542
- },
543
- };
544
- }
545
- // No existing message to reuse - create a new message
546
- const newMessage = {
547
- id: event.messageId,
548
- role: isAssistant ? "assistant" : "user",
549
- content: [],
550
- createdAt: new Date().toISOString(),
551
- };
552
- return {
553
- ...threadState,
554
- thread: {
555
- ...threadState.thread,
556
- messages: [...messages, newMessage],
557
- updatedAt: new Date().toISOString(),
558
- },
559
- streaming: {
560
- ...threadState.streaming,
561
- messageId: event.messageId,
562
- },
563
- };
564
- }
565
- /**
566
- * Handle TEXT_MESSAGE_CONTENT event.
567
- * Appends text content to the current message.
568
- * @param threadState - Current thread state
569
- * @param event - Text message content event
570
- * @returns Updated thread state
571
- */
572
- function handleTextMessageContent(threadState, event) {
573
- const messageId = event.messageId;
574
- const messages = threadState.thread.messages;
575
- // Find the message to update
576
- const messageIndex = messages.findIndex((m) => m.id === messageId);
577
- if (messageIndex === -1) {
578
- throw new Error(`Message ${messageId} not found for TEXT_MESSAGE_CONTENT event`);
579
- }
580
- const message = messages[messageIndex];
581
- const content = message.content;
582
- // Find or create text content block
583
- const lastContent = content[content.length - 1];
584
- const isTextBlock = lastContent?.type === "text";
585
- const updatedContent = isTextBlock
586
- ? [
587
- ...content.slice(0, -1),
588
- {
589
- ...lastContent,
590
- text: lastContent.text + event.delta,
591
- },
592
- ]
593
- : [
594
- ...content,
595
- {
596
- type: "text",
597
- text: event.delta,
598
- },
599
- ];
600
- const updatedMessage = {
601
- ...message,
602
- content: updatedContent,
603
- };
604
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
605
- }
606
- /**
607
- * Handle TEXT_MESSAGE_END event.
608
- * Marks the message as complete.
609
- * @param threadState - Current thread state
610
- * @param event - Text message end event
611
- * @returns Updated thread state
612
- */
613
- function handleTextMessageEnd(threadState, event) {
614
- const activeMessageId = threadState.streaming.messageId;
615
- if (activeMessageId && event.messageId !== activeMessageId) {
616
- throw new Error(`TEXT_MESSAGE_END messageId mismatch (thread ${threadState.thread.id}): expected ${activeMessageId}, got ${event.messageId}`);
617
- }
618
- return {
619
- ...threadState,
620
- streaming: {
621
- ...threadState.streaming,
622
- messageId: undefined,
623
- },
624
- };
625
- }
626
- /**
627
- * Handle TOOL_CALL_START event.
628
- * Adds a tool use content block to the current message.
629
- * If no message exists, creates a synthetic assistant message to hold the tool call.
630
- * @param threadState - Current thread state
631
- * @param event - Tool call start event
632
- * @returns Updated thread state
633
- */
634
- function handleToolCallStart(threadState, event) {
635
- const messageId = event.parentMessageId;
636
- const messages = threadState.thread.messages;
637
- // Find the parent message for this tool call.
638
- // If parentMessageId is provided, look it up directly.
639
- // Otherwise fall back to the last message, but only if it's an assistant message.
640
- // If the last message isn't assistant (e.g. it's the user message and the LLM
641
- // didn't produce any text before the tool call), we'll create a synthetic
642
- // assistant message below.
643
- let messageIndex;
644
- if (messageId) {
645
- messageIndex = messages.findIndex((m) => m.id === messageId);
646
- }
647
- else {
648
- const lastIndex = messages.length - 1;
649
- messageIndex =
650
- lastIndex >= 0 && messages[lastIndex].role === "assistant"
651
- ? lastIndex
652
- : -1;
653
- }
654
- const newContent = {
655
- type: "tool_use",
656
- id: event.toolCallId,
657
- name: event.toolCallName,
658
- input: {},
659
- };
660
- // If no suitable assistant message found, create a synthetic one for the tool call
661
- if (messageIndex === -1) {
662
- const syntheticMessageId = messageId ?? `msg_tool_${event.toolCallId}`;
663
- const syntheticMessage = {
664
- id: syntheticMessageId,
665
- role: "assistant",
666
- content: [newContent],
667
- createdAt: new Date().toISOString(),
668
- };
669
- return {
670
- ...threadState,
671
- thread: {
672
- ...threadState.thread,
673
- messages: [...messages, syntheticMessage],
674
- updatedAt: new Date().toISOString(),
675
- },
676
- streaming: {
677
- ...threadState.streaming,
678
- messageId: syntheticMessageId,
679
- },
680
- };
681
- }
682
- const message = messages[messageIndex];
683
- const updatedMessage = {
684
- ...message,
685
- content: [...message.content, newContent],
686
- };
687
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
688
- }
689
- /**
690
- * Handle TOOL_CALL_ARGS event.
691
- * Accumulates JSON string deltas for tool call arguments and optimistically
692
- * parses the partial JSON to update the tool_use content block in real-time.
693
- * When toolSchemas is provided, the parsed args are unstrictified so the
694
- * reducer always emits schema-valid values during streaming.
695
- * The final authoritative parse still happens at TOOL_CALL_END.
696
- * @param threadState - Current thread state
697
- * @param event - Tool call args event
698
- * @param parsedToolArgs - Pre-parsed args from the hook (already unstrictified)
699
- * @param toolSchemas - Original tool schemas for unstrictification
700
- * @returns Updated thread state
701
- */
702
- function handleToolCallArgs(threadState, event, parsedToolArgs, toolSchemas) {
703
- const toolCallId = event.toolCallId;
704
- // Accumulate the JSON string delta
705
- const accumulatedArgs = threadState.accumulatingToolArgs;
706
- const existingArgs = accumulatedArgs.get(toolCallId) ?? "";
707
- const newAccumulatedJson = existingArgs + event.delta;
708
- const newAccumulatedArgs = new Map(accumulatedArgs);
709
- newAccumulatedArgs.set(toolCallId, newAccumulatedJson);
710
- // Use pre-parsed args if provided, otherwise parse partial JSON ourselves
711
- let parsedInput = parsedToolArgs;
712
- if (!parsedInput) {
713
- try {
714
- const parsed = parsePartialJson(newAccumulatedJson);
715
- if (typeof parsed === "object" &&
716
- parsed !== null &&
717
- !Array.isArray(parsed)) {
718
- parsedInput = parsed;
719
- }
720
- }
721
- catch {
722
- // Partial JSON not parseable yet — leave input unchanged
723
- }
724
- }
725
- if (!parsedInput) {
726
- return {
727
- ...threadState,
728
- accumulatingToolArgs: newAccumulatedArgs,
729
- };
730
- }
731
- // Update the tool_use content block with partially parsed input
732
- const messages = threadState.thread.messages;
733
- const { messageIndex, contentIndex } = findContentById(messages, "tool_use", toolCallId, "TOOL_CALL_ARGS event");
734
- const message = messages[messageIndex];
735
- const toolUseContent = message.content[contentIndex];
736
- if (toolUseContent.type !== "tool_use") {
737
- throw new Error(`Content at index ${contentIndex} is not a tool_use block for TOOL_CALL_ARGS event`);
738
- }
739
- // Unstrictify if we have the original schema for this tool
740
- if (toolSchemas) {
741
- const schema = toolSchemas.get(toolUseContent.name);
742
- if (schema) {
743
- parsedInput = unstrictifyToolCallParamsFromSchema(schema, parsedInput);
744
- }
745
- }
746
- const updatedContent = {
747
- ...toolUseContent,
748
- input: parsedInput,
749
- };
750
- const updatedMessage = {
751
- ...message,
752
- content: updateContentAtIndex(message.content, contentIndex, updatedContent),
753
- };
754
- return {
755
- ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
756
- accumulatingToolArgs: newAccumulatedArgs,
757
- };
758
- }
759
- /**
760
- * Handle TOOL_CALL_END event.
761
- * Parses the accumulated JSON arguments, unstrictifies them if possible,
762
- * and updates the tool_use content block.
763
- * @param threadState - Current thread state
764
- * @param event - Tool call end event
765
- * @param toolSchemas - Original tool schemas for unstrictification
766
- * @returns Updated thread state
767
- */
768
- function handleToolCallEnd(threadState, event, toolSchemas) {
769
- const toolCallId = event.toolCallId;
770
- const messages = threadState.thread.messages;
771
- // Get accumulated JSON args string
772
- const accumulatedJson = threadState.accumulatingToolArgs.get(toolCallId);
773
- if (!accumulatedJson) {
774
- // No args accumulated - tool call has empty input
775
- return threadState;
776
- }
777
- // Parse the accumulated JSON - tool inputs are always objects
778
- let parsedInput;
779
- try {
780
- parsedInput = JSON.parse(accumulatedJson);
781
- }
782
- catch (error) {
783
- throw new Error(`Failed to parse tool call arguments for ${toolCallId}: ${error instanceof Error ? error.message : String(error)}. JSON: ${accumulatedJson}`);
784
- }
785
- // Find the tool_use content block
786
- const { messageIndex, contentIndex } = findContentById(messages, "tool_use", toolCallId, "TOOL_CALL_END event");
787
- const message = messages[messageIndex];
788
- const toolUseContent = message.content[contentIndex];
789
- if (toolUseContent.type !== "tool_use") {
790
- throw new Error(`Content at index ${contentIndex} is not a tool_use block for TOOL_CALL_END event`);
791
- }
792
- // Unstrictify parsed input if we have the original schema
793
- if (toolSchemas) {
794
- const schema = toolSchemas.get(toolUseContent.name);
795
- if (schema) {
796
- parsedInput = unstrictifyToolCallParamsFromSchema(schema, parsedInput);
797
- }
798
- }
799
- // Update the tool_use content with parsed input
800
- const updatedContent = {
801
- ...toolUseContent,
802
- input: parsedInput,
803
- };
804
- const updatedMessage = {
805
- ...message,
806
- content: updateContentAtIndex(message.content, contentIndex, updatedContent),
807
- };
808
- // Clear accumulated args for this tool call
809
- const newAccumulatingToolArgs = new Map(threadState.accumulatingToolArgs);
810
- newAccumulatingToolArgs.delete(toolCallId);
811
- return {
812
- ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
813
- accumulatingToolArgs: newAccumulatingToolArgs,
814
- };
815
- }
816
- /**
817
- * Handle TOOL_CALL_RESULT event.
818
- * Adds tool result to the specified message.
819
- * @param threadState - Current thread state
820
- * @param event - Tool call result event
821
- * @returns Updated thread state
822
- */
823
- function handleToolCallResult(threadState, event) {
824
- const messageId = event.messageId;
825
- const messages = threadState.thread.messages;
826
- // Find the message
827
- const messageIndex = messages.findIndex((m) => m.id === messageId);
828
- if (messageIndex === -1) {
829
- throw new Error(`Message ${messageId} not found for TOOL_CALL_RESULT event`);
830
- }
831
- const message = messages[messageIndex];
832
- // Add tool result content
833
- const newContent = {
834
- type: "tool_result",
835
- toolUseId: event.toolCallId,
836
- content: [
837
- {
838
- type: "text",
839
- text: event.content,
840
- },
841
- ],
842
- };
843
- const updatedMessage = {
844
- ...message,
845
- content: [...message.content, newContent],
846
- };
847
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
848
- }
849
- /**
850
- * Handle custom events (Tambo-specific).
851
- * @param threadState - Current thread state
852
- * @param event - Custom event (already narrowed from AGUIEvent)
853
- * @returns Updated thread state
854
- */
855
- function handleCustomEvent(threadState, event) {
856
- // Use centralized casting function to get properly typed Tambo event
857
- const customEvent = asTamboCustomEvent(event);
858
- if (!customEvent) {
859
- // Unknown custom event - log and return unchanged
860
- console.warn(`[StreamReducer] Unknown custom event name: ${event.name}`);
861
- return threadState;
862
- }
863
- switch (customEvent.name) {
864
- case "tambo.component.start":
865
- return handleComponentStart(threadState, customEvent);
866
- case "tambo.component.props_delta":
867
- return handleComponentDelta(threadState, customEvent, "props");
868
- case "tambo.component.state_delta":
869
- return handleComponentDelta(threadState, customEvent, "state");
870
- case "tambo.component.end":
871
- return handleComponentEnd(threadState, customEvent);
872
- case "tambo.run.awaiting_input":
873
- return handleRunAwaitingInput(threadState, customEvent);
874
- case "tambo.message.parent":
875
- return handleMessageParent(threadState, customEvent);
876
- default: {
877
- // Exhaustiveness check: if a new event type is added to TamboCustomEvent
878
- // and not handled here, TypeScript will error
879
- const _exhaustiveCheck = customEvent;
880
- throw new UnreachableCaseError(_exhaustiveCheck);
881
- }
882
- }
883
- }
884
- /**
885
- * Handle tambo.component.start event.
886
- * Adds a component content block to the message with 'started' streaming state.
887
- * @param threadState - Current thread state
888
- * @param event - Component start event
889
- * @returns Updated thread state
890
- */
891
- function handleComponentStart(threadState, event) {
892
- const messageId = event.value.messageId;
893
- let messages = threadState.thread.messages;
894
- // Find the message, or create it if it doesn't exist.
895
- // The backend may emit component events before TEXT_MESSAGE_START when
896
- // the LLM outputs a component tool call without preceding text.
897
- let messageIndex = messages.findIndex((m) => m.id === messageId);
898
- if (messageIndex === -1) {
899
- // Create a new assistant message for this component
900
- const newMessage = {
901
- id: messageId,
902
- role: "assistant",
903
- content: [],
904
- createdAt: new Date().toISOString(),
905
- };
906
- messages = [...messages, newMessage];
907
- messageIndex = messages.length - 1;
908
- // Update thread state with the new message before adding the component
909
- threadState = updateThreadMessages(threadState, messages);
910
- }
911
- const message = messages[messageIndex];
912
- // Add component content block with 'started' streaming state
913
- const newContent = {
914
- type: "component",
915
- id: event.value.componentId,
916
- name: event.value.componentName,
917
- props: {},
918
- streamingState: "started",
919
- };
920
- const updatedMessage = {
921
- ...message,
922
- content: [...message.content, newContent],
923
- };
924
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
925
- }
926
- /**
927
- * Handle component delta events (both props_delta and state_delta).
928
- * Applies JSON Patch to the specified field and sets streamingState to 'streaming'.
929
- * @param threadState - Current thread state
930
- * @param event - Component delta event (props or state)
931
- * @param field - Which field to update ('props' or 'state')
932
- * @returns Updated thread state
933
- */
934
- function handleComponentDelta(threadState, event, field) {
935
- const componentId = event.value.componentId;
936
- const operations = event.value.operations;
937
- const messages = threadState.thread.messages;
938
- const eventName = `tambo.component.${field}_delta`;
939
- // Find the component content block
940
- const { messageIndex, contentIndex } = findContentById(messages, "component", componentId, `${eventName} event`);
941
- const message = messages[messageIndex];
942
- const componentContent = message.content[contentIndex];
943
- if (componentContent.type !== "component") {
944
- throw new Error(`Content at index ${contentIndex} is not a component block for ${eventName} event`);
945
- }
946
- // Get current value (state defaults to {} if undefined)
947
- const currentValue = field === "props"
948
- ? componentContent.props
949
- : (componentContent.state ?? {});
950
- // Apply JSON Patch
951
- const updatedValue = applyJsonPatch(currentValue, operations);
952
- // Update field and set streaming state to 'streaming'
953
- const updatedContent = {
954
- ...componentContent,
955
- [field]: updatedValue,
956
- streamingState: "streaming",
957
- };
958
- const updatedMessage = {
959
- ...message,
960
- content: updateContentAtIndex(message.content, contentIndex, updatedContent),
961
- };
962
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
963
- }
964
- /**
965
- * Handle tambo.component.end event.
966
- * Sets component streaming state to 'done'.
967
- * @param threadState - Current thread state
968
- * @param event - Component end event
969
- * @returns Updated thread state
970
- */
971
- function handleComponentEnd(threadState, event) {
972
- const componentId = event.value.componentId;
973
- const messages = threadState.thread.messages;
974
- // Find the component content block
975
- const { messageIndex, contentIndex } = findContentById(messages, "component", componentId, "tambo.component.end event");
976
- const message = messages[messageIndex];
977
- const componentContent = message.content[contentIndex];
978
- if (componentContent.type !== "component") {
979
- throw new Error(`Content at index ${contentIndex} is not a component block for tambo.component.end event`);
980
- }
981
- // Set streaming state to 'done'
982
- const updatedContent = {
983
- ...componentContent,
984
- streamingState: "done",
985
- };
986
- const updatedMessage = {
987
- ...message,
988
- content: updateContentAtIndex(message.content, contentIndex, updatedContent),
989
- };
990
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
991
- }
992
- /**
993
- * Handle tambo.run.awaiting_input event.
994
- * Sets thread status to waiting for client-side tool execution.
995
- * @param threadState - Current thread state
996
- * @param _event - Run awaiting input event (unused)
997
- * @returns Updated thread state
998
- */
999
- function handleRunAwaitingInput(threadState, _event) {
1000
- return {
1001
- ...threadState,
1002
- thread: {
1003
- ...threadState.thread,
1004
- status: "waiting",
1005
- updatedAt: new Date().toISOString(),
1006
- },
1007
- streaming: {
1008
- ...threadState.streaming,
1009
- status: "waiting",
1010
- },
1011
- };
1012
- }
1013
- /**
1014
- * Handle tambo.message.parent event.
1015
- * Sets parentMessageId on the target message, creating a new empty assistant
1016
- * message if one doesn't already exist with the given ID.
1017
- *
1018
- * This event fires BEFORE TEXT_MESSAGE_START, so when handleTextMessageStart
1019
- * later finds/creates the message with the same ID, the parentMessageId will
1020
- * already be set.
1021
- * @param threadState - Current thread state
1022
- * @param event - Message parent event
1023
- * @returns Updated thread state
1024
- */
1025
- function handleMessageParent(threadState, event) {
1026
- const { messageId, parentMessageId } = event.value;
1027
- const messages = threadState.thread.messages;
1028
- // Find existing message or create a new empty assistant message
1029
- const messageIndex = messages.findIndex((m) => m.id === messageId);
1030
- if (messageIndex !== -1) {
1031
- // Message already exists - set parentMessageId on it
1032
- const message = messages[messageIndex];
1033
- const updatedMessage = {
1034
- ...message,
1035
- parentMessageId,
1036
- };
1037
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1038
- }
1039
- // Message doesn't exist yet - create a new empty assistant message
1040
- const newMessage = {
1041
- id: messageId,
1042
- role: "assistant",
1043
- content: [],
1044
- createdAt: new Date().toISOString(),
1045
- parentMessageId,
1046
- };
1047
- return updateThreadMessages(threadState, [...messages, newMessage]);
1048
- }
1049
- // ============================================================================
1050
- // Reasoning Event Handlers (currently mapped from THINKING_TEXT_MESSAGE_* events)
1051
- // ============================================================================
1052
- /**
1053
- * Generate an ephemeral message ID for reasoning messages that arrive before TEXT_MESSAGE_START.
1054
- * Uses crypto.randomUUID() which is available in Node.js 19+ and modern browsers.
1055
- */
1056
- function generateEphemeralMessageId() {
1057
- return `ephemeral_${crypto.randomUUID()}`;
1058
- }
1059
- /**
1060
- * Find or create an assistant message for reasoning events.
1061
- * Reasoning should only be attached to assistant messages.
1062
- * If no suitable assistant message exists, creates an ephemeral one.
1063
- * @param threadState - Current thread state
1064
- * @returns Object with messageIndex, messages array, and updated threadState
1065
- */
1066
- function findOrCreateMessageForReasoning(threadState) {
1067
- const messageId = threadState.streaming.messageId;
1068
- let messages = threadState.thread.messages;
1069
- // If we have an active streaming messageId, try to find it
1070
- if (messageId) {
1071
- const messageIndex = messages.findIndex((m) => m.id === messageId);
1072
- if (messageIndex !== -1 && messages[messageIndex].role === "assistant") {
1073
- return { messageIndex, messages, threadState };
1074
- }
1075
- }
1076
- // Look for the last assistant message
1077
- const lastAssistantIndex = messages.findLastIndex((m) => m.role === "assistant");
1078
- // If there's an assistant message and it's the most recent message, use it
1079
- // (Don't attach reasoning to an old assistant message if user message came after)
1080
- if (lastAssistantIndex !== -1 && lastAssistantIndex === messages.length - 1) {
1081
- return { messageIndex: lastAssistantIndex, messages, threadState };
1082
- }
1083
- // No suitable assistant message - create an ephemeral one
1084
- const ephemeralId = generateEphemeralMessageId();
1085
- const newMessage = {
1086
- id: ephemeralId,
1087
- role: "assistant",
1088
- content: [],
1089
- createdAt: new Date().toISOString(),
1090
- };
1091
- messages = [...messages, newMessage];
1092
- const messageIndex = messages.length - 1;
1093
- // Update thread state with new message
1094
- threadState = {
1095
- ...threadState,
1096
- thread: {
1097
- ...threadState.thread,
1098
- messages,
1099
- updatedAt: new Date().toISOString(),
1100
- },
1101
- streaming: {
1102
- ...threadState.streaming,
1103
- messageId: ephemeralId,
1104
- },
1105
- };
1106
- return { messageIndex, messages, threadState };
1107
- }
1108
- /**
1109
- * Handle THINKING_TEXT_MESSAGE_START event (will become REASONING_MESSAGE_START).
1110
- * Starts a new reasoning chunk by appending an empty string to the message's reasoning array.
1111
- * Records the start time for duration calculation.
1112
- * @param threadState - Current thread state
1113
- * @param event - Thinking text message start event
1114
- * @returns Updated thread state
1115
- */
1116
- function handleThinkingTextMessageStart(threadState, event) {
1117
- const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1118
- threadState = updatedThreadState;
1119
- const message = messages[messageIndex];
1120
- const existingReasoning = message.reasoning ?? [];
1121
- const updatedMessage = {
1122
- ...message,
1123
- reasoning: [...existingReasoning, ""],
1124
- };
1125
- // Record reasoning start time if this is the first reasoning chunk
1126
- const reasoningStartTime = threadState.streaming.reasoningStartTime ?? event.timestamp ?? Date.now();
1127
- return {
1128
- ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
1129
- streaming: {
1130
- ...threadState.streaming,
1131
- reasoningStartTime,
1132
- },
1133
- };
1134
- }
1135
- /**
1136
- * Handle THINKING_TEXT_MESSAGE_CONTENT event (will become REASONING_MESSAGE_CONTENT).
1137
- * Appends delta text to the last reasoning chunk.
1138
- * @param threadState - Current thread state
1139
- * @param event - Thinking text message content event
1140
- * @returns Updated thread state
1141
- */
1142
- function handleThinkingTextMessageContent(threadState, event) {
1143
- const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1144
- threadState = updatedThreadState;
1145
- const message = messages[messageIndex];
1146
- const existingReasoning = message.reasoning ?? [];
1147
- if (existingReasoning.length === 0) {
1148
- // No reasoning chunk started - start one implicitly
1149
- const updatedMessage = {
1150
- ...message,
1151
- reasoning: [event.delta],
1152
- };
1153
- return {
1154
- ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
1155
- streaming: {
1156
- ...threadState.streaming,
1157
- reasoningStartTime: threadState.streaming.reasoningStartTime ??
1158
- event.timestamp ??
1159
- Date.now(),
1160
- },
1161
- };
1162
- }
1163
- // Append to the last reasoning chunk
1164
- const updatedReasoning = [
1165
- ...existingReasoning.slice(0, -1),
1166
- existingReasoning[existingReasoning.length - 1] + event.delta,
1167
- ];
1168
- const updatedMessage = {
1169
- ...message,
1170
- reasoning: updatedReasoning,
1171
- };
1172
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1173
- }
1174
- /**
1175
- * Handle THINKING_TEXT_MESSAGE_END event (will become REASONING_MESSAGE_END).
1176
- * Calculates and stores the reasoning duration.
1177
- * @param threadState - Current thread state
1178
- * @param event - Thinking text message end event
1179
- * @returns Updated thread state
1180
- */
1181
- function handleThinkingTextMessageEnd(threadState, event) {
1182
- const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1183
- threadState = updatedThreadState;
1184
- const message = messages[messageIndex];
1185
- // Calculate duration if we have a start time
1186
- const reasoningStartTime = threadState.streaming.reasoningStartTime;
1187
- const endTime = event.timestamp ?? Date.now();
1188
- const reasoningDurationMS = reasoningStartTime
1189
- ? endTime - reasoningStartTime
1190
- : undefined;
1191
- const updatedMessage = {
1192
- ...message,
1193
- reasoningDurationMS: reasoningDurationMS ?? message.reasoningDurationMS ?? undefined,
1194
- };
1195
- return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1196
- }
1197
- /**
1198
- * Handle LOAD_THREAD_MESSAGES action.
1199
- * Loads messages from API into stream state for an existing thread.
1200
- * Deduplicates by message ID, keeping existing messages (they may have in-flight updates).
1201
- * Sorts merged messages by createdAt to ensure chronological order.
1202
- * @param state - Current stream state
1203
- * @param action - Load thread messages action
1204
- * @returns Updated stream state
1205
- */
1206
- function handleLoadThreadMessages(state, action) {
1207
- const { threadId, messages, skipIfStreaming } = action;
1208
- // Get or create thread state
1209
- let threadState = state.threadMap[threadId];
1210
- if (!threadState) {
1211
- threadState = createInitialThreadState(threadId);
1212
- }
1213
- // Skip if streaming and skipIfStreaming is true
1214
- if (skipIfStreaming && threadState.streaming.status === "streaming") {
1215
- return state;
1216
- }
1217
- const existingMessages = threadState.thread.messages;
1218
- // Build a set of existing message IDs for fast lookup
1219
- const existingIds = new Set(existingMessages.map((m) => m.id));
1220
- // Filter out messages that already exist (keep existing, add new).
1221
- // API-loaded messages are by definition fully complete, so stamp
1222
- // streamingState: "done" on all component content blocks. This is
1223
- // required by downstream hooks (usePropsStreamingStatus) which check
1224
- // streamingState === "done" to report isSuccess: true.
1225
- const newMessages = messages
1226
- .filter((m) => !existingIds.has(m.id))
1227
- .map((m) => ({
1228
- ...m,
1229
- content: m.content.map((block) => {
1230
- if (block.type !== "component")
1231
- return block;
1232
- if (block.streamingState !== undefined &&
1233
- block.streamingState !== "done") {
1234
- console.warn(`LOAD_THREAD_MESSAGES: component "${block.id}" has unexpected ` +
1235
- `streamingState "${block.streamingState}". API-loaded messages ` +
1236
- `should not have in-flight streaming state.`);
1237
- }
1238
- return { ...block, streamingState: "done" };
1239
- }),
1240
- }));
1241
- // Merge and sort by createdAt
1242
- const mergedMessages = [...existingMessages, ...newMessages].toSorted((a, b) => {
1243
- // Messages without createdAt go to the end
1244
- if (!a.createdAt && !b.createdAt)
1245
- return 0;
1246
- if (!a.createdAt)
1247
- return 1;
1248
- if (!b.createdAt)
1249
- return -1;
1250
- return a.createdAt.localeCompare(b.createdAt);
1251
- });
1252
- const updatedThreadState = {
1253
- ...threadState,
1254
- thread: {
1255
- ...threadState.thread,
1256
- messages: mergedMessages,
1257
- updatedAt: new Date().toISOString(),
1258
- },
1259
- };
1260
- return {
1261
- ...state,
1262
- threadMap: {
1263
- ...state.threadMap,
1264
- [threadId]: updatedThreadState,
1265
- },
1266
- };
1267
- }
1268
- //# sourceMappingURL=event-accumulator.js.map