@tambo-ai/react 0.73.0 → 0.74.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 (419) hide show
  1. package/README.md +12 -12
  2. package/dist/hooks/use-component-state.d.ts +1 -1
  3. package/dist/hooks/use-component-state.js.map +1 -1
  4. package/dist/hooks/use-streaming-props.d.ts +1 -1
  5. package/dist/hooks/use-streaming-props.js +1 -1
  6. package/dist/hooks/use-streaming-props.js.map +1 -1
  7. package/dist/hooks/use-tambo-stream-status.d.ts +1 -1
  8. package/dist/hooks/use-tambo-stream-status.js +1 -1
  9. package/dist/hooks/use-tambo-stream-status.js.map +1 -1
  10. package/dist/mcp/mcp-hooks.d.ts +4 -0
  11. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  12. package/dist/mcp/mcp-hooks.js +4 -0
  13. package/dist/mcp/mcp-hooks.js.map +1 -1
  14. package/dist/providers/tambo-interactable-provider-partial-updates.test.js +3 -3
  15. package/dist/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  16. package/dist/providers/tambo-interactable-provider.js +2 -2
  17. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  18. package/dist/providers/tambo-interactable-provider.test.js +3 -3
  19. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  20. package/dist/providers/tambo-provider.d.ts +3 -0
  21. package/dist/providers/tambo-provider.d.ts.map +1 -1
  22. package/dist/providers/tambo-provider.js +3 -0
  23. package/dist/providers/tambo-provider.js.map +1 -1
  24. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  25. package/dist/providers/tambo-thread-input-provider.js +1 -0
  26. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  27. package/dist/util/resource-content-resolver.d.ts.map +1 -1
  28. package/dist/util/resource-content-resolver.js +2 -0
  29. package/dist/util/resource-content-resolver.js.map +1 -1
  30. package/dist/v1/__tests__/v1-interactables.test.d.ts +2 -0
  31. package/dist/v1/__tests__/v1-interactables.test.d.ts.map +1 -0
  32. package/dist/v1/__tests__/v1-interactables.test.js +135 -0
  33. package/dist/v1/__tests__/v1-interactables.test.js.map +1 -0
  34. package/dist/v1/components/v1-component-renderer.d.ts +48 -0
  35. package/dist/v1/components/v1-component-renderer.d.ts.map +1 -0
  36. package/dist/v1/components/v1-component-renderer.js +137 -0
  37. package/dist/v1/components/v1-component-renderer.js.map +1 -0
  38. package/dist/v1/components/v1-component-renderer.test.d.ts +2 -0
  39. package/dist/v1/components/v1-component-renderer.test.d.ts.map +1 -0
  40. package/dist/v1/components/v1-component-renderer.test.js +270 -0
  41. package/dist/v1/components/v1-component-renderer.test.js.map +1 -0
  42. package/dist/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
  43. package/dist/v1/hooks/use-tambo-v1-component-state.js +2 -25
  44. package/dist/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  45. package/dist/v1/hooks/use-tambo-v1-component-state.test.js +2 -1
  46. package/dist/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  47. package/dist/v1/hooks/use-tambo-v1-messages.test.js +25 -1
  48. package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  49. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +18 -0
  50. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  51. package/dist/v1/hooks/use-tambo-v1-send-message.js +204 -17
  52. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  53. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +261 -7
  54. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  55. package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts +90 -0
  56. package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -0
  57. package/dist/v1/hooks/use-tambo-v1-stream-status.js +179 -0
  58. package/dist/v1/hooks/use-tambo-v1-stream-status.js.map +1 -0
  59. package/dist/v1/hooks/use-tambo-v1-stream-status.test.d.ts +2 -0
  60. package/dist/v1/hooks/use-tambo-v1-stream-status.test.d.ts.map +1 -0
  61. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js +371 -0
  62. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -0
  63. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts +78 -54
  64. package/dist/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -1
  65. package/dist/v1/hooks/use-tambo-v1-suggestions.js +153 -87
  66. package/dist/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
  67. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js +213 -134
  68. package/dist/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -1
  69. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +148 -13
  70. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  71. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +8 -21
  72. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  73. package/dist/v1/hooks/use-tambo-v1-thread-list.js +11 -10
  74. package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  75. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +37 -2
  76. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  77. package/dist/v1/hooks/use-tambo-v1-thread.d.ts +1 -1
  78. package/dist/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
  79. package/dist/v1/hooks/use-tambo-v1-thread.js +2 -7
  80. package/dist/v1/hooks/use-tambo-v1-thread.js.map +1 -1
  81. package/dist/v1/hooks/use-tambo-v1-thread.test.js +2 -0
  82. package/dist/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
  83. package/dist/v1/hooks/use-tambo-v1.d.ts +12 -28
  84. package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  85. package/dist/v1/hooks/use-tambo-v1.js +164 -31
  86. package/dist/v1/hooks/use-tambo-v1.js.map +1 -1
  87. package/dist/v1/hooks/use-tambo-v1.test.js +891 -18
  88. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
  89. package/dist/v1/index.d.ts +7 -1
  90. package/dist/v1/index.d.ts.map +1 -1
  91. package/dist/v1/index.js +18 -1
  92. package/dist/v1/index.js.map +1 -1
  93. package/dist/v1/providers/tambo-v1-provider.d.ts +16 -6
  94. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  95. package/dist/v1/providers/tambo-v1-provider.js +14 -19
  96. package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
  97. package/dist/v1/providers/tambo-v1-provider.test.js +34 -20
  98. package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
  99. package/dist/v1/providers/tambo-v1-stream-context.d.ts +3 -3
  100. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  101. package/dist/v1/providers/tambo-v1-stream-context.js +60 -12
  102. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
  103. package/dist/v1/providers/tambo-v1-stream-context.test.js +49 -20
  104. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  105. package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  106. package/dist/v1/providers/tambo-v1-stub-provider.js +2 -0
  107. package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  108. package/dist/v1/providers/tambo-v1-stub-provider.test.js +7 -6
  109. package/dist/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
  110. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +1 -6
  111. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  112. package/dist/v1/providers/tambo-v1-thread-input-provider.js +14 -12
  113. package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  114. package/dist/v1/types/event.d.ts +9 -1
  115. package/dist/v1/types/event.d.ts.map +1 -1
  116. package/dist/v1/types/event.js.map +1 -1
  117. package/dist/v1/types/event.test.js +5 -1
  118. package/dist/v1/types/event.test.js.map +1 -1
  119. package/dist/v1/types/message.d.ts +65 -7
  120. package/dist/v1/types/message.d.ts.map +1 -1
  121. package/dist/v1/types/message.js.map +1 -1
  122. package/dist/v1/types/thread.d.ts +4 -0
  123. package/dist/v1/types/thread.d.ts.map +1 -1
  124. package/dist/v1/types/thread.js.map +1 -1
  125. package/dist/v1/utils/event-accumulator.d.ts +40 -4
  126. package/dist/v1/utils/event-accumulator.d.ts.map +1 -1
  127. package/dist/v1/utils/event-accumulator.js +444 -35
  128. package/dist/v1/utils/event-accumulator.js.map +1 -1
  129. package/dist/v1/utils/event-accumulator.test.js +1041 -28
  130. package/dist/v1/utils/event-accumulator.test.js.map +1 -1
  131. package/dist/v1/utils/registry-conversion.d.ts +9 -9
  132. package/dist/v1/utils/registry-conversion.d.ts.map +1 -1
  133. package/dist/v1/utils/registry-conversion.js +10 -11
  134. package/dist/v1/utils/registry-conversion.js.map +1 -1
  135. package/dist/v1/utils/registry-conversion.test.js +39 -11
  136. package/dist/v1/utils/registry-conversion.test.js.map +1 -1
  137. package/dist/v1/utils/thread-utils.d.ts +16 -0
  138. package/dist/v1/utils/thread-utils.d.ts.map +1 -0
  139. package/dist/v1/utils/thread-utils.js +34 -0
  140. package/dist/v1/utils/thread-utils.js.map +1 -0
  141. package/dist/v1/utils/tool-executor.d.ts.map +1 -1
  142. package/dist/v1/utils/tool-executor.js +2 -0
  143. package/dist/v1/utils/tool-executor.js.map +1 -1
  144. package/dist/v1/utils/tool-executor.test.js +5 -0
  145. package/dist/v1/utils/tool-executor.test.js.map +1 -1
  146. package/esm/context-helpers/context-helpers-provider.test.js +2 -2
  147. package/esm/context-helpers/context-helpers.test.js +1 -1
  148. package/esm/context-helpers/current-interactables-context-helper.d.ts +1 -1
  149. package/esm/context-helpers/current-page-context-helper.d.ts +1 -1
  150. package/esm/context-helpers/current-time-context-helper.d.ts +1 -1
  151. package/esm/context-helpers/index.d.ts +4 -4
  152. package/esm/context-helpers/index.js +4 -4
  153. package/esm/hoc/with-tambo-interactable.d.ts +1 -1
  154. package/esm/hoc/with-tambo-interactable.js +2 -2
  155. package/esm/hoc/with-tambo-interactable.test.js +3 -3
  156. package/esm/hooks/index.d.ts +8 -8
  157. package/esm/hooks/index.js +8 -8
  158. package/esm/hooks/react-query-hooks.js +1 -1
  159. package/esm/hooks/use-component-state.d.ts +1 -1
  160. package/esm/hooks/use-component-state.js +3 -3
  161. package/esm/hooks/use-component-state.js.map +1 -1
  162. package/esm/hooks/use-component-state.test.js +5 -5
  163. package/esm/hooks/use-current-message.d.ts +1 -1
  164. package/esm/hooks/use-current-message.test.js +1 -1
  165. package/esm/hooks/use-message-images.test.js +1 -1
  166. package/esm/hooks/use-streaming-props.d.ts +1 -1
  167. package/esm/hooks/use-streaming-props.js +1 -1
  168. package/esm/hooks/use-streaming-props.js.map +1 -1
  169. package/esm/hooks/use-suggestions.d.ts +2 -2
  170. package/esm/hooks/use-suggestions.js +10 -10
  171. package/esm/hooks/use-suggestions.test.js +7 -7
  172. package/esm/hooks/use-tambo-stream-status.d.ts +1 -1
  173. package/esm/hooks/use-tambo-stream-status.js +4 -4
  174. package/esm/hooks/use-tambo-stream-status.js.map +1 -1
  175. package/esm/hooks/use-tambo-stream-status.test.js +4 -4
  176. package/esm/hooks/use-tambo-threads.js +3 -3
  177. package/esm/hooks/use-tambo-threads.test.js +3 -3
  178. package/esm/hooks/use-tambo-voice.js +2 -2
  179. package/esm/hooks/use-tambo-voice.test.js +3 -3
  180. package/esm/index.d.ts +22 -22
  181. package/esm/index.js +15 -15
  182. package/esm/mcp/elicitation.d.ts +1 -1
  183. package/esm/mcp/elicitation.test.js +1 -1
  184. package/esm/mcp/index.d.ts +7 -7
  185. package/esm/mcp/index.js +3 -3
  186. package/esm/mcp/mcp-client.d.ts +1 -1
  187. package/esm/mcp/mcp-client.js +1 -1
  188. package/esm/mcp/mcp-client.test.js +1 -1
  189. package/esm/mcp/mcp-hooks.d.ts +5 -1
  190. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  191. package/esm/mcp/mcp-hooks.js +8 -4
  192. package/esm/mcp/mcp-hooks.js.map +1 -1
  193. package/esm/mcp/mcp-hooks.test.js +6 -6
  194. package/esm/mcp/tambo-mcp-provider.d.ts +4 -4
  195. package/esm/mcp/tambo-mcp-provider.js +7 -7
  196. package/esm/mcp/tambo-mcp-provider.test.js +5 -5
  197. package/esm/mcp/use-mcp-servers.test.js +4 -4
  198. package/esm/model/generate-component-response.d.ts +1 -1
  199. package/esm/model/tambo-interactable.d.ts +1 -1
  200. package/esm/model/tambo-thread.d.ts +1 -1
  201. package/esm/providers/__tests__/thread-input-resource-resolution.test.js +3 -3
  202. package/esm/providers/hooks/use-tambo-session-token.test.js +1 -1
  203. package/esm/providers/index.d.ts +12 -12
  204. package/esm/providers/index.js +10 -10
  205. package/esm/providers/tambo-client-provider.js +1 -1
  206. package/esm/providers/tambo-client-provider.test.js +2 -2
  207. package/esm/providers/tambo-component-provider.d.ts +1 -1
  208. package/esm/providers/tambo-component-provider.js +2 -2
  209. package/esm/providers/tambo-context-attachment-provider.js +1 -1
  210. package/esm/providers/tambo-context-attachment-provider.test.js +2 -2
  211. package/esm/providers/tambo-context-helpers-provider.d.ts +1 -1
  212. package/esm/providers/tambo-context-helpers-provider.js +1 -1
  213. package/esm/providers/tambo-context-helpers-provider.test.js +2 -2
  214. package/esm/providers/tambo-interactable-provider-partial-updates.test.js +4 -4
  215. package/esm/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  216. package/esm/providers/tambo-interactable-provider.d.ts +5 -5
  217. package/esm/providers/tambo-interactable-provider.js +6 -6
  218. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  219. package/esm/providers/tambo-interactable-provider.test.js +4 -4
  220. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  221. package/esm/providers/tambo-interactables-additional-context-edge-cases.test.js +4 -4
  222. package/esm/providers/tambo-interactables-additional-context.test.js +4 -4
  223. package/esm/providers/tambo-mcp-token-provider.js +2 -2
  224. package/esm/providers/tambo-prop-stream-provider/index.d.ts +8 -8
  225. package/esm/providers/tambo-prop-stream-provider/index.js +9 -9
  226. package/esm/providers/tambo-prop-stream-provider/pending.d.ts +1 -1
  227. package/esm/providers/tambo-prop-stream-provider/pending.js +2 -2
  228. package/esm/providers/tambo-prop-stream-provider/provider.d.ts +1 -1
  229. package/esm/providers/tambo-prop-stream-provider/provider.js +2 -2
  230. package/esm/providers/tambo-prop-stream-provider/streaming.d.ts +1 -1
  231. package/esm/providers/tambo-prop-stream-provider/streaming.js +2 -2
  232. package/esm/providers/tambo-prop-stream-provider/success.d.ts +1 -1
  233. package/esm/providers/tambo-prop-stream-provider/success.js +2 -2
  234. package/esm/providers/tambo-prop-stream-provider/types.d.ts +1 -1
  235. package/esm/providers/tambo-prop-stream-provider.test.js +4 -4
  236. package/esm/providers/tambo-provider.d.ts +10 -7
  237. package/esm/providers/tambo-provider.d.ts.map +1 -1
  238. package/esm/providers/tambo-provider.js +13 -10
  239. package/esm/providers/tambo-provider.js.map +1 -1
  240. package/esm/providers/tambo-registry-provider.d.ts +3 -3
  241. package/esm/providers/tambo-registry-provider.js +3 -3
  242. package/esm/providers/tambo-registry-provider.test.js +2 -2
  243. package/esm/providers/tambo-registry-schema-compat.test.js +2 -2
  244. package/esm/providers/tambo-stubs.d.ts +4 -4
  245. package/esm/providers/tambo-stubs.js +9 -9
  246. package/esm/providers/tambo-stubs.test.js +2 -2
  247. package/esm/providers/tambo-thread-input-provider.d.ts +2 -2
  248. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  249. package/esm/providers/tambo-thread-input-provider.js +11 -10
  250. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  251. package/esm/providers/tambo-thread-provider-initial-messages.test.js +6 -6
  252. package/esm/providers/tambo-thread-provider.d.ts +2 -2
  253. package/esm/providers/tambo-thread-provider.js +8 -8
  254. package/esm/providers/tambo-thread-provider.test.js +7 -7
  255. package/esm/schema/index.d.ts +4 -4
  256. package/esm/schema/index.js +4 -4
  257. package/esm/schema/json-schema.test.js +1 -1
  258. package/esm/schema/schema.d.ts +1 -1
  259. package/esm/schema/schema.js +2 -2
  260. package/esm/schema/schema.test.js +3 -3
  261. package/esm/schema/standard-schema.test.js +1 -1
  262. package/esm/schema/validate.js +2 -2
  263. package/esm/schema/validate.test.js +1 -1
  264. package/esm/testing/tools.d.ts +3 -3
  265. package/esm/testing/tools.js +2 -2
  266. package/esm/util/content-parts.test.js +1 -1
  267. package/esm/util/generate-component.d.ts +2 -2
  268. package/esm/util/generate-component.js +4 -4
  269. package/esm/util/generate-component.test.js +2 -2
  270. package/esm/util/is-promise.test.js +1 -1
  271. package/esm/util/mcp-server-utils.d.ts +1 -1
  272. package/esm/util/mcp-server-utils.js +1 -1
  273. package/esm/util/mcp-server-utils.test.js +2 -2
  274. package/esm/util/message-builder.d.ts +1 -1
  275. package/esm/util/message-builder.test.js +1 -1
  276. package/esm/util/query-utils.test.js +1 -1
  277. package/esm/util/registry-validators.d.ts +1 -1
  278. package/esm/util/registry-validators.js +2 -2
  279. package/esm/util/registry-validators.test.js +1 -1
  280. package/esm/util/registry.d.ts +1 -1
  281. package/esm/util/registry.js +1 -1
  282. package/esm/util/registry.test.js +2 -2
  283. package/esm/util/resource-content-resolver.d.ts +2 -2
  284. package/esm/util/resource-content-resolver.d.ts.map +1 -1
  285. package/esm/util/resource-content-resolver.js +3 -1
  286. package/esm/util/resource-content-resolver.js.map +1 -1
  287. package/esm/util/resource-content-resolver.test.js +3 -3
  288. package/esm/util/resource-validators.d.ts +1 -1
  289. package/esm/util/resource-validators.test.js +1 -1
  290. package/esm/util/tool-caller.d.ts +1 -1
  291. package/esm/util/tool-caller.js +1 -1
  292. package/esm/util/validate-component-name.test.js +1 -1
  293. package/esm/v1/__tests__/v1-interactables.test.d.ts +2 -0
  294. package/esm/v1/__tests__/v1-interactables.test.d.ts.map +1 -0
  295. package/esm/v1/__tests__/v1-interactables.test.js +130 -0
  296. package/esm/v1/__tests__/v1-interactables.test.js.map +1 -0
  297. package/esm/v1/components/v1-component-renderer.d.ts +48 -0
  298. package/esm/v1/components/v1-component-renderer.d.ts.map +1 -0
  299. package/esm/v1/components/v1-component-renderer.js +100 -0
  300. package/esm/v1/components/v1-component-renderer.js.map +1 -0
  301. package/esm/v1/components/v1-component-renderer.test.d.ts +2 -0
  302. package/esm/v1/components/v1-component-renderer.test.d.ts.map +1 -0
  303. package/esm/v1/components/v1-component-renderer.test.js +265 -0
  304. package/esm/v1/components/v1-component-renderer.test.js.map +1 -0
  305. package/esm/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
  306. package/esm/v1/hooks/use-tambo-v1-component-state.js +4 -27
  307. package/esm/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  308. package/esm/v1/hooks/use-tambo-v1-component-state.test.js +6 -5
  309. package/esm/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  310. package/esm/v1/hooks/use-tambo-v1-messages.d.ts +1 -1
  311. package/esm/v1/hooks/use-tambo-v1-messages.js +1 -1
  312. package/esm/v1/hooks/use-tambo-v1-messages.test.js +27 -3
  313. package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  314. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +20 -2
  315. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  316. package/esm/v1/hooks/use-tambo-v1-send-message.js +213 -26
  317. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  318. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +266 -12
  319. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  320. package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts +90 -0
  321. package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -0
  322. package/esm/v1/hooks/use-tambo-v1-stream-status.js +176 -0
  323. package/esm/v1/hooks/use-tambo-v1-stream-status.js.map +1 -0
  324. package/esm/v1/hooks/use-tambo-v1-stream-status.test.d.ts +2 -0
  325. package/esm/v1/hooks/use-tambo-v1-stream-status.test.d.ts.map +1 -0
  326. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js +369 -0
  327. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -0
  328. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts +78 -54
  329. package/esm/v1/hooks/use-tambo-v1-suggestions.d.ts.map +1 -1
  330. package/esm/v1/hooks/use-tambo-v1-suggestions.js +157 -91
  331. package/esm/v1/hooks/use-tambo-v1-suggestions.js.map +1 -1
  332. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js +218 -139
  333. package/esm/v1/hooks/use-tambo-v1-suggestions.test.js.map +1 -1
  334. package/esm/v1/hooks/use-tambo-v1-thread-input.d.ts +1 -1
  335. package/esm/v1/hooks/use-tambo-v1-thread-input.js +1 -1
  336. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +151 -16
  337. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  338. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +8 -21
  339. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  340. package/esm/v1/hooks/use-tambo-v1-thread-list.js +12 -11
  341. package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  342. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +39 -4
  343. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  344. package/esm/v1/hooks/use-tambo-v1-thread.d.ts +1 -1
  345. package/esm/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
  346. package/esm/v1/hooks/use-tambo-v1-thread.js +3 -8
  347. package/esm/v1/hooks/use-tambo-v1-thread.js.map +1 -1
  348. package/esm/v1/hooks/use-tambo-v1-thread.test.js +4 -2
  349. package/esm/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
  350. package/esm/v1/hooks/use-tambo-v1.d.ts +15 -31
  351. package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  352. package/esm/v1/hooks/use-tambo-v1.js +134 -34
  353. package/esm/v1/hooks/use-tambo-v1.js.map +1 -1
  354. package/esm/v1/hooks/use-tambo-v1.test.js +862 -19
  355. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
  356. package/esm/v1/index.d.ts +28 -22
  357. package/esm/v1/index.d.ts.map +1 -1
  358. package/esm/v1/index.js +30 -18
  359. package/esm/v1/index.js.map +1 -1
  360. package/esm/v1/providers/tambo-v1-provider.d.ts +21 -11
  361. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  362. package/esm/v1/providers/tambo-v1-provider.js +20 -25
  363. package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
  364. package/esm/v1/providers/tambo-v1-provider.test.js +40 -26
  365. package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
  366. package/esm/v1/providers/tambo-v1-stream-context.d.ts +4 -4
  367. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  368. package/esm/v1/providers/tambo-v1-stream-context.js +62 -14
  369. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
  370. package/esm/v1/providers/tambo-v1-stream-context.test.js +50 -21
  371. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  372. package/esm/v1/providers/tambo-v1-stub-provider.d.ts +3 -3
  373. package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  374. package/esm/v1/providers/tambo-v1-stub-provider.js +7 -5
  375. package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  376. package/esm/v1/providers/tambo-v1-stub-provider.test.js +12 -11
  377. package/esm/v1/providers/tambo-v1-stub-provider.test.js.map +1 -1
  378. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +3 -8
  379. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  380. package/esm/v1/providers/tambo-v1-thread-input-provider.js +18 -16
  381. package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  382. package/esm/v1/types/event.d.ts +9 -1
  383. package/esm/v1/types/event.d.ts.map +1 -1
  384. package/esm/v1/types/event.js.map +1 -1
  385. package/esm/v1/types/event.test.js +6 -2
  386. package/esm/v1/types/event.test.js.map +1 -1
  387. package/esm/v1/types/message.d.ts +65 -7
  388. package/esm/v1/types/message.d.ts.map +1 -1
  389. package/esm/v1/types/message.js.map +1 -1
  390. package/esm/v1/types/thread.d.ts +5 -1
  391. package/esm/v1/types/thread.d.ts.map +1 -1
  392. package/esm/v1/types/thread.js.map +1 -1
  393. package/esm/v1/utils/component-renderer.test.js +1 -1
  394. package/esm/v1/utils/event-accumulator.d.ts +41 -5
  395. package/esm/v1/utils/event-accumulator.d.ts.map +1 -1
  396. package/esm/v1/utils/event-accumulator.js +444 -36
  397. package/esm/v1/utils/event-accumulator.js.map +1 -1
  398. package/esm/v1/utils/event-accumulator.test.js +1042 -29
  399. package/esm/v1/utils/event-accumulator.test.js.map +1 -1
  400. package/esm/v1/utils/json-patch.test.js +1 -1
  401. package/esm/v1/utils/registry-conversion.d.ts +9 -9
  402. package/esm/v1/utils/registry-conversion.d.ts.map +1 -1
  403. package/esm/v1/utils/registry-conversion.js +11 -12
  404. package/esm/v1/utils/registry-conversion.js.map +1 -1
  405. package/esm/v1/utils/registry-conversion.test.js +40 -12
  406. package/esm/v1/utils/registry-conversion.test.js.map +1 -1
  407. package/esm/v1/utils/stream-handler.test.js +1 -1
  408. package/esm/v1/utils/thread-utils.d.ts +16 -0
  409. package/esm/v1/utils/thread-utils.d.ts.map +1 -0
  410. package/esm/v1/utils/thread-utils.js +31 -0
  411. package/esm/v1/utils/thread-utils.js.map +1 -0
  412. package/esm/v1/utils/tool-call-tracker.d.ts +1 -1
  413. package/esm/v1/utils/tool-executor.d.ts +1 -1
  414. package/esm/v1/utils/tool-executor.d.ts.map +1 -1
  415. package/esm/v1/utils/tool-executor.js +2 -0
  416. package/esm/v1/utils/tool-executor.js.map +1 -1
  417. package/esm/v1/utils/tool-executor.test.js +6 -1
  418. package/esm/v1/utils/tool-executor.test.js.map +1 -1
  419. package/package.json +11 -10
@@ -5,8 +5,9 @@
5
5
  * Used with useReducer to accumulate events into thread state.
6
6
  */
7
7
  import { EventType } from "@ag-ui/core";
8
- import { asTamboCustomEvent, } from "../types/event";
9
- import { applyJsonPatch } from "./json-patch";
8
+ import { asTamboCustomEvent, } from "../types/event.js";
9
+ import { parse as parsePartialJson } from "partial-json";
10
+ import { applyJsonPatch } from "./json-patch.js";
10
11
  /**
11
12
  * Error thrown when an unreachable case is reached in a switch statement.
12
13
  * This indicates a programming error where not all cases were handled.
@@ -37,19 +38,36 @@ export function createInitialThreadState(threadId) {
37
38
  status: "idle",
38
39
  createdAt: now,
39
40
  updatedAt: now,
41
+ lastRunCancelled: false,
40
42
  },
41
43
  streaming: initialStreamingState,
42
44
  accumulatingToolArgs: new Map(),
43
45
  };
44
46
  }
45
47
  /**
46
- * Create initial stream state with empty threadMap.
48
+ * Placeholder thread ID used for new threads before they get a real ID from the server.
49
+ * This allows optimistic UI updates (showing user messages immediately) before the
50
+ * server responds with the actual thread ID.
51
+ */
52
+ export const PLACEHOLDER_THREAD_ID = "placeholder";
53
+ /**
54
+ * Check if a thread ID is a placeholder (not a real API thread ID).
55
+ * @param threadId - Thread ID to check
56
+ * @returns True if this is a placeholder thread ID
57
+ */
58
+ export function isPlaceholderThreadId(threadId) {
59
+ return threadId === PLACEHOLDER_THREAD_ID;
60
+ }
61
+ /**
62
+ * Create initial stream state with placeholder thread.
47
63
  * @returns Initial stream state
48
64
  */
49
65
  export function createInitialState() {
50
66
  return {
51
- threadMap: {},
52
- currentThreadId: null,
67
+ threadMap: {
68
+ [PLACEHOLDER_THREAD_ID]: createInitialThreadState(PLACEHOLDER_THREAD_ID),
69
+ },
70
+ currentThreadId: PLACEHOLDER_THREAD_ID,
53
71
  };
54
72
  }
55
73
  /**
@@ -193,28 +211,85 @@ export function streamReducer(state, action) {
193
211
  currentThreadId: threadId,
194
212
  };
195
213
  }
214
+ case "LOAD_THREAD_MESSAGES": {
215
+ return handleLoadThreadMessages(state, action);
216
+ }
217
+ case "UPDATE_THREAD_TITLE": {
218
+ const threadState = state.threadMap[action.threadId];
219
+ if (!threadState) {
220
+ return state;
221
+ }
222
+ return {
223
+ ...state,
224
+ threadMap: {
225
+ ...state.threadMap,
226
+ [action.threadId]: {
227
+ ...threadState,
228
+ thread: {
229
+ ...threadState.thread,
230
+ title: action.title,
231
+ },
232
+ },
233
+ },
234
+ };
235
+ }
196
236
  case "EVENT":
197
237
  // Fall through to event handling below
198
238
  break;
199
239
  }
200
240
  // Handle EVENT action
201
241
  const { event, threadId } = action;
242
+ const effectiveThreadId = event.type === EventType.RUN_STARTED ? event.threadId : threadId;
202
243
  // Get the current thread state, auto-initializing if needed
203
244
  // Auto-initialization handles the case where events arrive before explicit thread init
204
245
  // (e.g., when creating a new thread and RUN_STARTED is the first event)
205
- let threadState = state.threadMap[threadId];
246
+ let threadState = state.threadMap[effectiveThreadId];
206
247
  let updatedState = state;
207
248
  if (!threadState) {
208
249
  // Auto-initialize the thread to avoid dropping events
209
- threadState = createInitialThreadState(threadId);
250
+ threadState = createInitialThreadState(effectiveThreadId);
210
251
  updatedState = {
211
252
  ...state,
212
253
  threadMap: {
213
254
  ...state.threadMap,
214
- [threadId]: threadState,
255
+ [effectiveThreadId]: threadState,
215
256
  },
216
257
  };
217
258
  }
259
+ // Handle placeholder thread migration for RUN_STARTED events
260
+ // When a new thread is created, messages may have been added to the placeholder thread
261
+ // for immediate UI feedback. Now that we have the real threadId, migrate those messages.
262
+ if (event.type === EventType.RUN_STARTED &&
263
+ effectiveThreadId !== PLACEHOLDER_THREAD_ID) {
264
+ const placeholderState = updatedState.threadMap[PLACEHOLDER_THREAD_ID];
265
+ if (placeholderState?.thread.messages.length) {
266
+ // Prepend placeholder thread messages to the real thread
267
+ threadState = {
268
+ ...threadState,
269
+ thread: {
270
+ ...threadState.thread,
271
+ messages: [
272
+ ...placeholderState.thread.messages,
273
+ ...threadState.thread.messages,
274
+ ],
275
+ },
276
+ };
277
+ // Reset placeholder thread to empty state
278
+ const resetPlaceholder = createInitialThreadState(PLACEHOLDER_THREAD_ID);
279
+ updatedState = {
280
+ ...updatedState,
281
+ threadMap: {
282
+ ...updatedState.threadMap,
283
+ [PLACEHOLDER_THREAD_ID]: resetPlaceholder,
284
+ [effectiveThreadId]: threadState,
285
+ },
286
+ // Only switch selection if the user is currently on the placeholder thread
287
+ currentThreadId: isPlaceholderThreadId(updatedState.currentThreadId)
288
+ ? effectiveThreadId
289
+ : updatedState.currentThreadId,
290
+ };
291
+ }
292
+ }
218
293
  // Process the event for this specific thread
219
294
  let updatedThreadState;
220
295
  // Switch on event.type - AGUIEvent is a discriminated union so TypeScript
@@ -253,11 +328,17 @@ export function streamReducer(state, action) {
253
328
  case EventType.CUSTOM:
254
329
  updatedThreadState = handleCustomEvent(threadState, event);
255
330
  break;
256
- // Unsupported AG-UI event types - may be added in future phases
257
- case EventType.TEXT_MESSAGE_CHUNK:
258
331
  case EventType.THINKING_TEXT_MESSAGE_START:
332
+ updatedThreadState = handleThinkingTextMessageStart(threadState, event);
333
+ break;
259
334
  case EventType.THINKING_TEXT_MESSAGE_CONTENT:
335
+ updatedThreadState = handleThinkingTextMessageContent(threadState, event);
336
+ break;
260
337
  case EventType.THINKING_TEXT_MESSAGE_END:
338
+ updatedThreadState = handleThinkingTextMessageEnd(threadState, event);
339
+ break;
340
+ // Unsupported AG-UI event types - may be added in future phases
341
+ case EventType.TEXT_MESSAGE_CHUNK:
261
342
  case EventType.TOOL_CALL_CHUNK:
262
343
  case EventType.THINKING_START:
263
344
  case EventType.THINKING_END:
@@ -285,7 +366,7 @@ export function streamReducer(state, action) {
285
366
  ...updatedState,
286
367
  threadMap: {
287
368
  ...updatedState.threadMap,
288
- [threadId]: updatedThreadState,
369
+ [effectiveThreadId]: updatedThreadState,
289
370
  },
290
371
  };
291
372
  }
@@ -302,6 +383,8 @@ function handleRunStarted(threadState, event) {
302
383
  ...threadState.thread,
303
384
  status: "streaming",
304
385
  updatedAt: new Date().toISOString(),
386
+ // Reset lastRunCancelled when a new run starts
387
+ lastRunCancelled: false,
305
388
  },
306
389
  streaming: {
307
390
  status: "streaming",
@@ -332,39 +415,78 @@ function handleRunFinished(threadState, _event) {
332
415
  }
333
416
  /**
334
417
  * Handle RUN_ERROR event.
418
+ * Sets lastRunCancelled if the error code is "CANCELLED".
335
419
  * @param threadState - Current thread state
336
420
  * @param event - Run error event
337
421
  * @returns Updated thread state
338
422
  */
339
423
  function handleRunError(threadState, event) {
424
+ const isCancelled = event.code === "CANCELLED";
340
425
  return {
341
426
  ...threadState,
342
427
  thread: {
343
428
  ...threadState.thread,
344
- status: "error",
429
+ // Use "idle" status for cancelled runs (not a real error from user perspective)
430
+ status: isCancelled ? "idle" : "error",
345
431
  updatedAt: new Date().toISOString(),
432
+ lastRunCancelled: isCancelled,
346
433
  },
347
434
  streaming: {
348
435
  ...threadState.streaming,
349
- status: "error",
350
- error: {
351
- message: event.message,
352
- code: event.code,
353
- },
436
+ // Use "idle" status for cancelled runs so UI shows as not streaming
437
+ status: isCancelled ? "idle" : "error",
438
+ error: isCancelled
439
+ ? undefined
440
+ : {
441
+ message: event.message,
442
+ code: event.code,
443
+ },
354
444
  },
355
445
  };
356
446
  }
357
447
  /**
358
448
  * Handle TEXT_MESSAGE_START event.
359
- * Creates a new message in the thread.
449
+ * Creates a new message or reuses an ephemeral reasoning message.
360
450
  * @param threadState - Current thread state
361
451
  * @param event - Text message start event
362
452
  * @returns Updated thread state
363
453
  */
364
454
  function handleTextMessageStart(threadState, event) {
455
+ const isAssistant = event.role !== "user";
456
+ const messages = threadState.thread.messages;
457
+ // For assistant messages, check if there's an ephemeral message with reasoning
458
+ // that we should merge into instead of creating a new message.
459
+ if (isAssistant) {
460
+ const ephemeralIndex = messages.findIndex((m) => m.role === "assistant" &&
461
+ m.id.startsWith("ephemeral_") &&
462
+ m.reasoning &&
463
+ m.reasoning.length > 0);
464
+ if (ephemeralIndex !== -1) {
465
+ // Update the ephemeral message with the real ID
466
+ const ephemeralMessage = messages[ephemeralIndex];
467
+ const updatedMessages = [...messages];
468
+ updatedMessages[ephemeralIndex] = {
469
+ ...ephemeralMessage,
470
+ id: event.messageId,
471
+ };
472
+ return {
473
+ ...threadState,
474
+ thread: {
475
+ ...threadState.thread,
476
+ messages: updatedMessages,
477
+ updatedAt: new Date().toISOString(),
478
+ },
479
+ streaming: {
480
+ ...threadState.streaming,
481
+ messageId: event.messageId,
482
+ },
483
+ };
484
+ }
485
+ }
486
+ // No ephemeral message to reuse - create a new message
365
487
  const newMessage = {
366
488
  id: event.messageId,
367
- role: event.role === "user" ? "user" : "assistant",
489
+ role: isAssistant ? "assistant" : "user",
368
490
  content: [],
369
491
  createdAt: new Date().toISOString(),
370
492
  };
@@ -372,7 +494,7 @@ function handleTextMessageStart(threadState, event) {
372
494
  ...threadState,
373
495
  thread: {
374
496
  ...threadState.thread,
375
- messages: [...threadState.thread.messages, newMessage],
497
+ messages: [...messages, newMessage],
376
498
  updatedAt: new Date().toISOString(),
377
499
  },
378
500
  streaming: {
@@ -445,6 +567,7 @@ function handleTextMessageEnd(threadState, event) {
445
567
  /**
446
568
  * Handle TOOL_CALL_START event.
447
569
  * Adds a tool use content block to the current message.
570
+ * If no message exists, creates a synthetic assistant message to hold the tool call.
448
571
  * @param threadState - Current thread state
449
572
  * @param event - Tool call start event
450
573
  * @returns Updated thread state
@@ -456,18 +579,35 @@ function handleToolCallStart(threadState, event) {
456
579
  const messageIndex = messageId
457
580
  ? messages.findIndex((m) => m.id === messageId)
458
581
  : messages.length - 1;
459
- if (messageIndex === -1) {
460
- throw new Error(messageId
461
- ? `Message ${messageId} not found for TOOL_CALL_START event`
462
- : `No messages exist for TOOL_CALL_START event`);
463
- }
464
- const message = messages[messageIndex];
465
582
  const newContent = {
466
583
  type: "tool_use",
467
584
  id: event.toolCallId,
468
585
  name: event.toolCallName,
469
586
  input: {},
470
587
  };
588
+ // If no message found, create a synthetic assistant message for the tool call
589
+ if (messageIndex === -1) {
590
+ const syntheticMessageId = messageId ?? `msg_tool_${event.toolCallId}`;
591
+ const syntheticMessage = {
592
+ id: syntheticMessageId,
593
+ role: "assistant",
594
+ content: [newContent],
595
+ createdAt: new Date().toISOString(),
596
+ };
597
+ return {
598
+ ...threadState,
599
+ thread: {
600
+ ...threadState.thread,
601
+ messages: [...messages, syntheticMessage],
602
+ updatedAt: new Date().toISOString(),
603
+ },
604
+ streaming: {
605
+ ...threadState.streaming,
606
+ messageId: syntheticMessageId,
607
+ },
608
+ };
609
+ }
610
+ const message = messages[messageIndex];
471
611
  const updatedMessage = {
472
612
  ...message,
473
613
  content: [...message.content, newContent],
@@ -476,8 +616,9 @@ function handleToolCallStart(threadState, event) {
476
616
  }
477
617
  /**
478
618
  * Handle TOOL_CALL_ARGS event.
479
- * Accumulates JSON string deltas for tool call arguments.
480
- * The accumulated string will be parsed at TOOL_CALL_END.
619
+ * Accumulates JSON string deltas for tool call arguments and optimistically
620
+ * parses the partial JSON to update the tool_use content block in real-time.
621
+ * The final authoritative parse still happens at TOOL_CALL_END.
481
622
  * @param threadState - Current thread state
482
623
  * @param event - Tool call args event
483
624
  * @returns Updated thread state
@@ -487,10 +628,46 @@ function handleToolCallArgs(threadState, event) {
487
628
  // Accumulate the JSON string delta
488
629
  const accumulatedArgs = threadState.accumulatingToolArgs;
489
630
  const existingArgs = accumulatedArgs.get(toolCallId) ?? "";
631
+ const newAccumulatedJson = existingArgs + event.delta;
490
632
  const newAccumulatedArgs = new Map(accumulatedArgs);
491
- newAccumulatedArgs.set(toolCallId, existingArgs + event.delta);
633
+ newAccumulatedArgs.set(toolCallId, newAccumulatedJson);
634
+ // Optimistically parse partial JSON to update the tool_use content block
635
+ let parsedInput;
636
+ try {
637
+ const parsed = parsePartialJson(newAccumulatedJson);
638
+ if (typeof parsed === "object" &&
639
+ parsed !== null &&
640
+ !Array.isArray(parsed)) {
641
+ parsedInput = parsed;
642
+ }
643
+ }
644
+ catch {
645
+ // Partial JSON not parseable yet — leave input unchanged
646
+ }
647
+ if (!parsedInput) {
648
+ return {
649
+ ...threadState,
650
+ accumulatingToolArgs: newAccumulatedArgs,
651
+ };
652
+ }
653
+ // Update the tool_use content block with partially parsed input
654
+ const messages = threadState.thread.messages;
655
+ const { messageIndex, contentIndex } = findContentById(messages, "tool_use", toolCallId, "TOOL_CALL_ARGS event");
656
+ const message = messages[messageIndex];
657
+ const toolUseContent = message.content[contentIndex];
658
+ if (toolUseContent.type !== "tool_use") {
659
+ throw new Error(`Content at index ${contentIndex} is not a tool_use block for TOOL_CALL_ARGS event`);
660
+ }
661
+ const updatedContent = {
662
+ ...toolUseContent,
663
+ input: parsedInput,
664
+ };
665
+ const updatedMessage = {
666
+ ...message,
667
+ content: updateContentAtIndex(message.content, contentIndex, updatedContent),
668
+ };
492
669
  return {
493
- ...threadState,
670
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
494
671
  accumulatingToolArgs: newAccumulatedArgs,
495
672
  };
496
673
  }
@@ -510,7 +687,7 @@ function handleToolCallEnd(threadState, event) {
510
687
  // No args accumulated - tool call has empty input
511
688
  return threadState;
512
689
  }
513
- // Parse the accumulated JSON
690
+ // Parse the accumulated JSON - tool inputs are always objects
514
691
  let parsedInput;
515
692
  try {
516
693
  parsedInput = JSON.parse(accumulatedJson);
@@ -544,7 +721,7 @@ function handleToolCallEnd(threadState, event) {
544
721
  }
545
722
  /**
546
723
  * Handle TOOL_CALL_RESULT event.
547
- * Adds tool result to the message.
724
+ * Adds tool result to the specified message.
548
725
  * @param threadState - Current thread state
549
726
  * @param event - Tool call result event
550
727
  * @returns Updated thread state
@@ -617,11 +794,23 @@ function handleCustomEvent(threadState, event) {
617
794
  */
618
795
  function handleComponentStart(threadState, event) {
619
796
  const messageId = event.value.messageId;
620
- const messages = threadState.thread.messages;
621
- // Find the message
622
- const messageIndex = messages.findIndex((m) => m.id === messageId);
797
+ let messages = threadState.thread.messages;
798
+ // Find the message, or create it if it doesn't exist.
799
+ // The backend may emit component events before TEXT_MESSAGE_START when
800
+ // the LLM outputs a component tool call without preceding text.
801
+ let messageIndex = messages.findIndex((m) => m.id === messageId);
623
802
  if (messageIndex === -1) {
624
- throw new Error(`Message ${messageId} not found for tambo.component.start event`);
803
+ // Create a new assistant message for this component
804
+ const newMessage = {
805
+ id: messageId,
806
+ role: "assistant",
807
+ content: [],
808
+ createdAt: new Date().toISOString(),
809
+ };
810
+ messages = [...messages, newMessage];
811
+ messageIndex = messages.length - 1;
812
+ // Update thread state with the new message before adding the component
813
+ threadState = updateThreadMessages(threadState, messages);
625
814
  }
626
815
  const message = messages[messageIndex];
627
816
  // Add component content block with 'started' streaming state
@@ -725,4 +914,223 @@ function handleRunAwaitingInput(threadState, _event) {
725
914
  },
726
915
  };
727
916
  }
917
+ // ============================================================================
918
+ // Reasoning Event Handlers (currently mapped from THINKING_TEXT_MESSAGE_* events)
919
+ // ============================================================================
920
+ /**
921
+ * Generate an ephemeral message ID for reasoning messages that arrive before TEXT_MESSAGE_START.
922
+ * Uses crypto.randomUUID() which is available in Node.js 19+ and modern browsers.
923
+ */
924
+ function generateEphemeralMessageId() {
925
+ return `ephemeral_${crypto.randomUUID()}`;
926
+ }
927
+ /**
928
+ * Find or create an assistant message for reasoning events.
929
+ * Reasoning should only be attached to assistant messages.
930
+ * If no suitable assistant message exists, creates an ephemeral one.
931
+ * @param threadState - Current thread state
932
+ * @returns Object with messageIndex, messages array, and updated threadState
933
+ */
934
+ function findOrCreateMessageForReasoning(threadState) {
935
+ const messageId = threadState.streaming.messageId;
936
+ let messages = threadState.thread.messages;
937
+ // If we have an active streaming messageId, try to find it
938
+ if (messageId) {
939
+ const messageIndex = messages.findIndex((m) => m.id === messageId);
940
+ if (messageIndex !== -1 && messages[messageIndex].role === "assistant") {
941
+ return { messageIndex, messages, threadState };
942
+ }
943
+ }
944
+ // Look for the last assistant message
945
+ const lastAssistantIndex = messages.findLastIndex((m) => m.role === "assistant");
946
+ // If there's an assistant message and it's the most recent message, use it
947
+ // (Don't attach reasoning to an old assistant message if user message came after)
948
+ if (lastAssistantIndex !== -1 && lastAssistantIndex === messages.length - 1) {
949
+ return { messageIndex: lastAssistantIndex, messages, threadState };
950
+ }
951
+ // No suitable assistant message - create an ephemeral one
952
+ const ephemeralId = generateEphemeralMessageId();
953
+ const newMessage = {
954
+ id: ephemeralId,
955
+ role: "assistant",
956
+ content: [],
957
+ createdAt: new Date().toISOString(),
958
+ };
959
+ messages = [...messages, newMessage];
960
+ const messageIndex = messages.length - 1;
961
+ // Update thread state with new message
962
+ threadState = {
963
+ ...threadState,
964
+ thread: {
965
+ ...threadState.thread,
966
+ messages,
967
+ updatedAt: new Date().toISOString(),
968
+ },
969
+ streaming: {
970
+ ...threadState.streaming,
971
+ messageId: ephemeralId,
972
+ },
973
+ };
974
+ return { messageIndex, messages, threadState };
975
+ }
976
+ /**
977
+ * Handle THINKING_TEXT_MESSAGE_START event (will become REASONING_MESSAGE_START).
978
+ * Starts a new reasoning chunk by appending an empty string to the message's reasoning array.
979
+ * Records the start time for duration calculation.
980
+ * @param threadState - Current thread state
981
+ * @param event - Thinking text message start event
982
+ * @returns Updated thread state
983
+ */
984
+ function handleThinkingTextMessageStart(threadState, event) {
985
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
986
+ threadState = updatedThreadState;
987
+ const message = messages[messageIndex];
988
+ const existingReasoning = message.reasoning ?? [];
989
+ const updatedMessage = {
990
+ ...message,
991
+ reasoning: [...existingReasoning, ""],
992
+ };
993
+ // Record reasoning start time if this is the first reasoning chunk
994
+ const reasoningStartTime = threadState.streaming.reasoningStartTime ?? event.timestamp ?? Date.now();
995
+ return {
996
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
997
+ streaming: {
998
+ ...threadState.streaming,
999
+ reasoningStartTime,
1000
+ },
1001
+ };
1002
+ }
1003
+ /**
1004
+ * Handle THINKING_TEXT_MESSAGE_CONTENT event (will become REASONING_MESSAGE_CONTENT).
1005
+ * Appends delta text to the last reasoning chunk.
1006
+ * @param threadState - Current thread state
1007
+ * @param event - Thinking text message content event
1008
+ * @returns Updated thread state
1009
+ */
1010
+ function handleThinkingTextMessageContent(threadState, event) {
1011
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1012
+ threadState = updatedThreadState;
1013
+ const message = messages[messageIndex];
1014
+ const existingReasoning = message.reasoning ?? [];
1015
+ if (existingReasoning.length === 0) {
1016
+ // No reasoning chunk started - start one implicitly
1017
+ const updatedMessage = {
1018
+ ...message,
1019
+ reasoning: [event.delta],
1020
+ };
1021
+ return {
1022
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
1023
+ streaming: {
1024
+ ...threadState.streaming,
1025
+ reasoningStartTime: threadState.streaming.reasoningStartTime ??
1026
+ event.timestamp ??
1027
+ Date.now(),
1028
+ },
1029
+ };
1030
+ }
1031
+ // Append to the last reasoning chunk
1032
+ const updatedReasoning = [
1033
+ ...existingReasoning.slice(0, -1),
1034
+ existingReasoning[existingReasoning.length - 1] + event.delta,
1035
+ ];
1036
+ const updatedMessage = {
1037
+ ...message,
1038
+ reasoning: updatedReasoning,
1039
+ };
1040
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1041
+ }
1042
+ /**
1043
+ * Handle THINKING_TEXT_MESSAGE_END event (will become REASONING_MESSAGE_END).
1044
+ * Calculates and stores the reasoning duration.
1045
+ * @param threadState - Current thread state
1046
+ * @param event - Thinking text message end event
1047
+ * @returns Updated thread state
1048
+ */
1049
+ function handleThinkingTextMessageEnd(threadState, event) {
1050
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1051
+ threadState = updatedThreadState;
1052
+ const message = messages[messageIndex];
1053
+ // Calculate duration if we have a start time
1054
+ const reasoningStartTime = threadState.streaming.reasoningStartTime;
1055
+ const endTime = event.timestamp ?? Date.now();
1056
+ const reasoningDurationMS = reasoningStartTime
1057
+ ? endTime - reasoningStartTime
1058
+ : undefined;
1059
+ const updatedMessage = {
1060
+ ...message,
1061
+ reasoningDurationMS: reasoningDurationMS ?? message.reasoningDurationMS ?? undefined,
1062
+ };
1063
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1064
+ }
1065
+ /**
1066
+ * Handle LOAD_THREAD_MESSAGES action.
1067
+ * Loads messages from API into stream state for an existing thread.
1068
+ * Deduplicates by message ID, keeping existing messages (they may have in-flight updates).
1069
+ * Sorts merged messages by createdAt to ensure chronological order.
1070
+ * @param state - Current stream state
1071
+ * @param action - Load thread messages action
1072
+ * @returns Updated stream state
1073
+ */
1074
+ function handleLoadThreadMessages(state, action) {
1075
+ const { threadId, messages, skipIfStreaming } = action;
1076
+ // Get or create thread state
1077
+ let threadState = state.threadMap[threadId];
1078
+ if (!threadState) {
1079
+ threadState = createInitialThreadState(threadId);
1080
+ }
1081
+ // Skip if streaming and skipIfStreaming is true
1082
+ if (skipIfStreaming && threadState.streaming.status === "streaming") {
1083
+ return state;
1084
+ }
1085
+ const existingMessages = threadState.thread.messages;
1086
+ // Build a set of existing message IDs for fast lookup
1087
+ const existingIds = new Set(existingMessages.map((m) => m.id));
1088
+ // Filter out messages that already exist (keep existing, add new).
1089
+ // API-loaded messages are by definition fully complete, so stamp
1090
+ // streamingState: "done" on all component content blocks. This is
1091
+ // required by downstream hooks (usePropsStreamingStatus) which check
1092
+ // streamingState === "done" to report isSuccess: true.
1093
+ const newMessages = messages
1094
+ .filter((m) => !existingIds.has(m.id))
1095
+ .map((m) => ({
1096
+ ...m,
1097
+ content: m.content.map((block) => {
1098
+ if (block.type !== "component")
1099
+ return block;
1100
+ if (block.streamingState !== undefined &&
1101
+ block.streamingState !== "done") {
1102
+ console.warn(`LOAD_THREAD_MESSAGES: component "${block.id}" has unexpected ` +
1103
+ `streamingState "${block.streamingState}". API-loaded messages ` +
1104
+ `should not have in-flight streaming state.`);
1105
+ }
1106
+ return { ...block, streamingState: "done" };
1107
+ }),
1108
+ }));
1109
+ // Merge and sort by createdAt
1110
+ const mergedMessages = [...existingMessages, ...newMessages].toSorted((a, b) => {
1111
+ // Messages without createdAt go to the end
1112
+ if (!a.createdAt && !b.createdAt)
1113
+ return 0;
1114
+ if (!a.createdAt)
1115
+ return 1;
1116
+ if (!b.createdAt)
1117
+ return -1;
1118
+ return a.createdAt.localeCompare(b.createdAt);
1119
+ });
1120
+ const updatedThreadState = {
1121
+ ...threadState,
1122
+ thread: {
1123
+ ...threadState.thread,
1124
+ messages: mergedMessages,
1125
+ updatedAt: new Date().toISOString(),
1126
+ },
1127
+ };
1128
+ return {
1129
+ ...state,
1130
+ threadMap: {
1131
+ ...state.threadMap,
1132
+ [threadId]: updatedThreadState,
1133
+ },
1134
+ };
1135
+ }
728
1136
  //# sourceMappingURL=event-accumulator.js.map