@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
@@ -6,12 +6,14 @@
6
6
  * Used with useReducer to accumulate events into thread state.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.UnreachableCaseError = void 0;
9
+ exports.PLACEHOLDER_THREAD_ID = exports.UnreachableCaseError = void 0;
10
10
  exports.createInitialThreadState = createInitialThreadState;
11
+ exports.isPlaceholderThreadId = isPlaceholderThreadId;
11
12
  exports.createInitialState = createInitialState;
12
13
  exports.streamReducer = streamReducer;
13
14
  const core_1 = require("@ag-ui/core");
14
15
  const event_1 = require("../types/event");
16
+ const partial_json_1 = require("partial-json");
15
17
  const json_patch_1 = require("./json-patch");
16
18
  /**
17
19
  * Error thrown when an unreachable case is reached in a switch statement.
@@ -44,19 +46,36 @@ function createInitialThreadState(threadId) {
44
46
  status: "idle",
45
47
  createdAt: now,
46
48
  updatedAt: now,
49
+ lastRunCancelled: false,
47
50
  },
48
51
  streaming: initialStreamingState,
49
52
  accumulatingToolArgs: new Map(),
50
53
  };
51
54
  }
52
55
  /**
53
- * Create initial stream state with empty threadMap.
56
+ * Placeholder thread ID used for new threads before they get a real ID from the server.
57
+ * This allows optimistic UI updates (showing user messages immediately) before the
58
+ * server responds with the actual thread ID.
59
+ */
60
+ exports.PLACEHOLDER_THREAD_ID = "placeholder";
61
+ /**
62
+ * Check if a thread ID is a placeholder (not a real API thread ID).
63
+ * @param threadId - Thread ID to check
64
+ * @returns True if this is a placeholder thread ID
65
+ */
66
+ function isPlaceholderThreadId(threadId) {
67
+ return threadId === exports.PLACEHOLDER_THREAD_ID;
68
+ }
69
+ /**
70
+ * Create initial stream state with placeholder thread.
54
71
  * @returns Initial stream state
55
72
  */
56
73
  function createInitialState() {
57
74
  return {
58
- threadMap: {},
59
- currentThreadId: null,
75
+ threadMap: {
76
+ [exports.PLACEHOLDER_THREAD_ID]: createInitialThreadState(exports.PLACEHOLDER_THREAD_ID),
77
+ },
78
+ currentThreadId: exports.PLACEHOLDER_THREAD_ID,
60
79
  };
61
80
  }
62
81
  /**
@@ -200,28 +219,85 @@ function streamReducer(state, action) {
200
219
  currentThreadId: threadId,
201
220
  };
202
221
  }
222
+ case "LOAD_THREAD_MESSAGES": {
223
+ return handleLoadThreadMessages(state, action);
224
+ }
225
+ case "UPDATE_THREAD_TITLE": {
226
+ const threadState = state.threadMap[action.threadId];
227
+ if (!threadState) {
228
+ return state;
229
+ }
230
+ return {
231
+ ...state,
232
+ threadMap: {
233
+ ...state.threadMap,
234
+ [action.threadId]: {
235
+ ...threadState,
236
+ thread: {
237
+ ...threadState.thread,
238
+ title: action.title,
239
+ },
240
+ },
241
+ },
242
+ };
243
+ }
203
244
  case "EVENT":
204
245
  // Fall through to event handling below
205
246
  break;
206
247
  }
207
248
  // Handle EVENT action
208
249
  const { event, threadId } = action;
250
+ const effectiveThreadId = event.type === core_1.EventType.RUN_STARTED ? event.threadId : threadId;
209
251
  // Get the current thread state, auto-initializing if needed
210
252
  // Auto-initialization handles the case where events arrive before explicit thread init
211
253
  // (e.g., when creating a new thread and RUN_STARTED is the first event)
212
- let threadState = state.threadMap[threadId];
254
+ let threadState = state.threadMap[effectiveThreadId];
213
255
  let updatedState = state;
214
256
  if (!threadState) {
215
257
  // Auto-initialize the thread to avoid dropping events
216
- threadState = createInitialThreadState(threadId);
258
+ threadState = createInitialThreadState(effectiveThreadId);
217
259
  updatedState = {
218
260
  ...state,
219
261
  threadMap: {
220
262
  ...state.threadMap,
221
- [threadId]: threadState,
263
+ [effectiveThreadId]: threadState,
222
264
  },
223
265
  };
224
266
  }
267
+ // Handle placeholder thread migration for RUN_STARTED events
268
+ // When a new thread is created, messages may have been added to the placeholder thread
269
+ // for immediate UI feedback. Now that we have the real threadId, migrate those messages.
270
+ if (event.type === core_1.EventType.RUN_STARTED &&
271
+ effectiveThreadId !== exports.PLACEHOLDER_THREAD_ID) {
272
+ const placeholderState = updatedState.threadMap[exports.PLACEHOLDER_THREAD_ID];
273
+ if (placeholderState?.thread.messages.length) {
274
+ // Prepend placeholder thread messages to the real thread
275
+ threadState = {
276
+ ...threadState,
277
+ thread: {
278
+ ...threadState.thread,
279
+ messages: [
280
+ ...placeholderState.thread.messages,
281
+ ...threadState.thread.messages,
282
+ ],
283
+ },
284
+ };
285
+ // Reset placeholder thread to empty state
286
+ const resetPlaceholder = createInitialThreadState(exports.PLACEHOLDER_THREAD_ID);
287
+ updatedState = {
288
+ ...updatedState,
289
+ threadMap: {
290
+ ...updatedState.threadMap,
291
+ [exports.PLACEHOLDER_THREAD_ID]: resetPlaceholder,
292
+ [effectiveThreadId]: threadState,
293
+ },
294
+ // Only switch selection if the user is currently on the placeholder thread
295
+ currentThreadId: isPlaceholderThreadId(updatedState.currentThreadId)
296
+ ? effectiveThreadId
297
+ : updatedState.currentThreadId,
298
+ };
299
+ }
300
+ }
225
301
  // Process the event for this specific thread
226
302
  let updatedThreadState;
227
303
  // Switch on event.type - AGUIEvent is a discriminated union so TypeScript
@@ -260,11 +336,17 @@ function streamReducer(state, action) {
260
336
  case core_1.EventType.CUSTOM:
261
337
  updatedThreadState = handleCustomEvent(threadState, event);
262
338
  break;
263
- // Unsupported AG-UI event types - may be added in future phases
264
- case core_1.EventType.TEXT_MESSAGE_CHUNK:
265
339
  case core_1.EventType.THINKING_TEXT_MESSAGE_START:
340
+ updatedThreadState = handleThinkingTextMessageStart(threadState, event);
341
+ break;
266
342
  case core_1.EventType.THINKING_TEXT_MESSAGE_CONTENT:
343
+ updatedThreadState = handleThinkingTextMessageContent(threadState, event);
344
+ break;
267
345
  case core_1.EventType.THINKING_TEXT_MESSAGE_END:
346
+ updatedThreadState = handleThinkingTextMessageEnd(threadState, event);
347
+ break;
348
+ // Unsupported AG-UI event types - may be added in future phases
349
+ case core_1.EventType.TEXT_MESSAGE_CHUNK:
268
350
  case core_1.EventType.TOOL_CALL_CHUNK:
269
351
  case core_1.EventType.THINKING_START:
270
352
  case core_1.EventType.THINKING_END:
@@ -292,7 +374,7 @@ function streamReducer(state, action) {
292
374
  ...updatedState,
293
375
  threadMap: {
294
376
  ...updatedState.threadMap,
295
- [threadId]: updatedThreadState,
377
+ [effectiveThreadId]: updatedThreadState,
296
378
  },
297
379
  };
298
380
  }
@@ -309,6 +391,8 @@ function handleRunStarted(threadState, event) {
309
391
  ...threadState.thread,
310
392
  status: "streaming",
311
393
  updatedAt: new Date().toISOString(),
394
+ // Reset lastRunCancelled when a new run starts
395
+ lastRunCancelled: false,
312
396
  },
313
397
  streaming: {
314
398
  status: "streaming",
@@ -339,39 +423,78 @@ function handleRunFinished(threadState, _event) {
339
423
  }
340
424
  /**
341
425
  * Handle RUN_ERROR event.
426
+ * Sets lastRunCancelled if the error code is "CANCELLED".
342
427
  * @param threadState - Current thread state
343
428
  * @param event - Run error event
344
429
  * @returns Updated thread state
345
430
  */
346
431
  function handleRunError(threadState, event) {
432
+ const isCancelled = event.code === "CANCELLED";
347
433
  return {
348
434
  ...threadState,
349
435
  thread: {
350
436
  ...threadState.thread,
351
- status: "error",
437
+ // Use "idle" status for cancelled runs (not a real error from user perspective)
438
+ status: isCancelled ? "idle" : "error",
352
439
  updatedAt: new Date().toISOString(),
440
+ lastRunCancelled: isCancelled,
353
441
  },
354
442
  streaming: {
355
443
  ...threadState.streaming,
356
- status: "error",
357
- error: {
358
- message: event.message,
359
- code: event.code,
360
- },
444
+ // Use "idle" status for cancelled runs so UI shows as not streaming
445
+ status: isCancelled ? "idle" : "error",
446
+ error: isCancelled
447
+ ? undefined
448
+ : {
449
+ message: event.message,
450
+ code: event.code,
451
+ },
361
452
  },
362
453
  };
363
454
  }
364
455
  /**
365
456
  * Handle TEXT_MESSAGE_START event.
366
- * Creates a new message in the thread.
457
+ * Creates a new message or reuses an ephemeral reasoning message.
367
458
  * @param threadState - Current thread state
368
459
  * @param event - Text message start event
369
460
  * @returns Updated thread state
370
461
  */
371
462
  function handleTextMessageStart(threadState, event) {
463
+ const isAssistant = event.role !== "user";
464
+ const messages = threadState.thread.messages;
465
+ // For assistant messages, check if there's an ephemeral message with reasoning
466
+ // that we should merge into instead of creating a new message.
467
+ if (isAssistant) {
468
+ const ephemeralIndex = messages.findIndex((m) => m.role === "assistant" &&
469
+ m.id.startsWith("ephemeral_") &&
470
+ m.reasoning &&
471
+ m.reasoning.length > 0);
472
+ if (ephemeralIndex !== -1) {
473
+ // Update the ephemeral message with the real ID
474
+ const ephemeralMessage = messages[ephemeralIndex];
475
+ const updatedMessages = [...messages];
476
+ updatedMessages[ephemeralIndex] = {
477
+ ...ephemeralMessage,
478
+ id: event.messageId,
479
+ };
480
+ return {
481
+ ...threadState,
482
+ thread: {
483
+ ...threadState.thread,
484
+ messages: updatedMessages,
485
+ updatedAt: new Date().toISOString(),
486
+ },
487
+ streaming: {
488
+ ...threadState.streaming,
489
+ messageId: event.messageId,
490
+ },
491
+ };
492
+ }
493
+ }
494
+ // No ephemeral message to reuse - create a new message
372
495
  const newMessage = {
373
496
  id: event.messageId,
374
- role: event.role === "user" ? "user" : "assistant",
497
+ role: isAssistant ? "assistant" : "user",
375
498
  content: [],
376
499
  createdAt: new Date().toISOString(),
377
500
  };
@@ -379,7 +502,7 @@ function handleTextMessageStart(threadState, event) {
379
502
  ...threadState,
380
503
  thread: {
381
504
  ...threadState.thread,
382
- messages: [...threadState.thread.messages, newMessage],
505
+ messages: [...messages, newMessage],
383
506
  updatedAt: new Date().toISOString(),
384
507
  },
385
508
  streaming: {
@@ -452,6 +575,7 @@ function handleTextMessageEnd(threadState, event) {
452
575
  /**
453
576
  * Handle TOOL_CALL_START event.
454
577
  * Adds a tool use content block to the current message.
578
+ * If no message exists, creates a synthetic assistant message to hold the tool call.
455
579
  * @param threadState - Current thread state
456
580
  * @param event - Tool call start event
457
581
  * @returns Updated thread state
@@ -463,18 +587,35 @@ function handleToolCallStart(threadState, event) {
463
587
  const messageIndex = messageId
464
588
  ? messages.findIndex((m) => m.id === messageId)
465
589
  : messages.length - 1;
466
- if (messageIndex === -1) {
467
- throw new Error(messageId
468
- ? `Message ${messageId} not found for TOOL_CALL_START event`
469
- : `No messages exist for TOOL_CALL_START event`);
470
- }
471
- const message = messages[messageIndex];
472
590
  const newContent = {
473
591
  type: "tool_use",
474
592
  id: event.toolCallId,
475
593
  name: event.toolCallName,
476
594
  input: {},
477
595
  };
596
+ // If no message found, create a synthetic assistant message for the tool call
597
+ if (messageIndex === -1) {
598
+ const syntheticMessageId = messageId ?? `msg_tool_${event.toolCallId}`;
599
+ const syntheticMessage = {
600
+ id: syntheticMessageId,
601
+ role: "assistant",
602
+ content: [newContent],
603
+ createdAt: new Date().toISOString(),
604
+ };
605
+ return {
606
+ ...threadState,
607
+ thread: {
608
+ ...threadState.thread,
609
+ messages: [...messages, syntheticMessage],
610
+ updatedAt: new Date().toISOString(),
611
+ },
612
+ streaming: {
613
+ ...threadState.streaming,
614
+ messageId: syntheticMessageId,
615
+ },
616
+ };
617
+ }
618
+ const message = messages[messageIndex];
478
619
  const updatedMessage = {
479
620
  ...message,
480
621
  content: [...message.content, newContent],
@@ -483,8 +624,9 @@ function handleToolCallStart(threadState, event) {
483
624
  }
484
625
  /**
485
626
  * Handle TOOL_CALL_ARGS event.
486
- * Accumulates JSON string deltas for tool call arguments.
487
- * The accumulated string will be parsed at TOOL_CALL_END.
627
+ * Accumulates JSON string deltas for tool call arguments and optimistically
628
+ * parses the partial JSON to update the tool_use content block in real-time.
629
+ * The final authoritative parse still happens at TOOL_CALL_END.
488
630
  * @param threadState - Current thread state
489
631
  * @param event - Tool call args event
490
632
  * @returns Updated thread state
@@ -494,10 +636,46 @@ function handleToolCallArgs(threadState, event) {
494
636
  // Accumulate the JSON string delta
495
637
  const accumulatedArgs = threadState.accumulatingToolArgs;
496
638
  const existingArgs = accumulatedArgs.get(toolCallId) ?? "";
639
+ const newAccumulatedJson = existingArgs + event.delta;
497
640
  const newAccumulatedArgs = new Map(accumulatedArgs);
498
- newAccumulatedArgs.set(toolCallId, existingArgs + event.delta);
641
+ newAccumulatedArgs.set(toolCallId, newAccumulatedJson);
642
+ // Optimistically parse partial JSON to update the tool_use content block
643
+ let parsedInput;
644
+ try {
645
+ const parsed = (0, partial_json_1.parse)(newAccumulatedJson);
646
+ if (typeof parsed === "object" &&
647
+ parsed !== null &&
648
+ !Array.isArray(parsed)) {
649
+ parsedInput = parsed;
650
+ }
651
+ }
652
+ catch {
653
+ // Partial JSON not parseable yet — leave input unchanged
654
+ }
655
+ if (!parsedInput) {
656
+ return {
657
+ ...threadState,
658
+ accumulatingToolArgs: newAccumulatedArgs,
659
+ };
660
+ }
661
+ // Update the tool_use content block with partially parsed input
662
+ const messages = threadState.thread.messages;
663
+ const { messageIndex, contentIndex } = findContentById(messages, "tool_use", toolCallId, "TOOL_CALL_ARGS event");
664
+ const message = messages[messageIndex];
665
+ const toolUseContent = message.content[contentIndex];
666
+ if (toolUseContent.type !== "tool_use") {
667
+ throw new Error(`Content at index ${contentIndex} is not a tool_use block for TOOL_CALL_ARGS event`);
668
+ }
669
+ const updatedContent = {
670
+ ...toolUseContent,
671
+ input: parsedInput,
672
+ };
673
+ const updatedMessage = {
674
+ ...message,
675
+ content: updateContentAtIndex(message.content, contentIndex, updatedContent),
676
+ };
499
677
  return {
500
- ...threadState,
678
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
501
679
  accumulatingToolArgs: newAccumulatedArgs,
502
680
  };
503
681
  }
@@ -517,7 +695,7 @@ function handleToolCallEnd(threadState, event) {
517
695
  // No args accumulated - tool call has empty input
518
696
  return threadState;
519
697
  }
520
- // Parse the accumulated JSON
698
+ // Parse the accumulated JSON - tool inputs are always objects
521
699
  let parsedInput;
522
700
  try {
523
701
  parsedInput = JSON.parse(accumulatedJson);
@@ -551,7 +729,7 @@ function handleToolCallEnd(threadState, event) {
551
729
  }
552
730
  /**
553
731
  * Handle TOOL_CALL_RESULT event.
554
- * Adds tool result to the message.
732
+ * Adds tool result to the specified message.
555
733
  * @param threadState - Current thread state
556
734
  * @param event - Tool call result event
557
735
  * @returns Updated thread state
@@ -624,11 +802,23 @@ function handleCustomEvent(threadState, event) {
624
802
  */
625
803
  function handleComponentStart(threadState, event) {
626
804
  const messageId = event.value.messageId;
627
- const messages = threadState.thread.messages;
628
- // Find the message
629
- const messageIndex = messages.findIndex((m) => m.id === messageId);
805
+ let messages = threadState.thread.messages;
806
+ // Find the message, or create it if it doesn't exist.
807
+ // The backend may emit component events before TEXT_MESSAGE_START when
808
+ // the LLM outputs a component tool call without preceding text.
809
+ let messageIndex = messages.findIndex((m) => m.id === messageId);
630
810
  if (messageIndex === -1) {
631
- throw new Error(`Message ${messageId} not found for tambo.component.start event`);
811
+ // Create a new assistant message for this component
812
+ const newMessage = {
813
+ id: messageId,
814
+ role: "assistant",
815
+ content: [],
816
+ createdAt: new Date().toISOString(),
817
+ };
818
+ messages = [...messages, newMessage];
819
+ messageIndex = messages.length - 1;
820
+ // Update thread state with the new message before adding the component
821
+ threadState = updateThreadMessages(threadState, messages);
632
822
  }
633
823
  const message = messages[messageIndex];
634
824
  // Add component content block with 'started' streaming state
@@ -732,4 +922,223 @@ function handleRunAwaitingInput(threadState, _event) {
732
922
  },
733
923
  };
734
924
  }
925
+ // ============================================================================
926
+ // Reasoning Event Handlers (currently mapped from THINKING_TEXT_MESSAGE_* events)
927
+ // ============================================================================
928
+ /**
929
+ * Generate an ephemeral message ID for reasoning messages that arrive before TEXT_MESSAGE_START.
930
+ * Uses crypto.randomUUID() which is available in Node.js 19+ and modern browsers.
931
+ */
932
+ function generateEphemeralMessageId() {
933
+ return `ephemeral_${crypto.randomUUID()}`;
934
+ }
935
+ /**
936
+ * Find or create an assistant message for reasoning events.
937
+ * Reasoning should only be attached to assistant messages.
938
+ * If no suitable assistant message exists, creates an ephemeral one.
939
+ * @param threadState - Current thread state
940
+ * @returns Object with messageIndex, messages array, and updated threadState
941
+ */
942
+ function findOrCreateMessageForReasoning(threadState) {
943
+ const messageId = threadState.streaming.messageId;
944
+ let messages = threadState.thread.messages;
945
+ // If we have an active streaming messageId, try to find it
946
+ if (messageId) {
947
+ const messageIndex = messages.findIndex((m) => m.id === messageId);
948
+ if (messageIndex !== -1 && messages[messageIndex].role === "assistant") {
949
+ return { messageIndex, messages, threadState };
950
+ }
951
+ }
952
+ // Look for the last assistant message
953
+ const lastAssistantIndex = messages.findLastIndex((m) => m.role === "assistant");
954
+ // If there's an assistant message and it's the most recent message, use it
955
+ // (Don't attach reasoning to an old assistant message if user message came after)
956
+ if (lastAssistantIndex !== -1 && lastAssistantIndex === messages.length - 1) {
957
+ return { messageIndex: lastAssistantIndex, messages, threadState };
958
+ }
959
+ // No suitable assistant message - create an ephemeral one
960
+ const ephemeralId = generateEphemeralMessageId();
961
+ const newMessage = {
962
+ id: ephemeralId,
963
+ role: "assistant",
964
+ content: [],
965
+ createdAt: new Date().toISOString(),
966
+ };
967
+ messages = [...messages, newMessage];
968
+ const messageIndex = messages.length - 1;
969
+ // Update thread state with new message
970
+ threadState = {
971
+ ...threadState,
972
+ thread: {
973
+ ...threadState.thread,
974
+ messages,
975
+ updatedAt: new Date().toISOString(),
976
+ },
977
+ streaming: {
978
+ ...threadState.streaming,
979
+ messageId: ephemeralId,
980
+ },
981
+ };
982
+ return { messageIndex, messages, threadState };
983
+ }
984
+ /**
985
+ * Handle THINKING_TEXT_MESSAGE_START event (will become REASONING_MESSAGE_START).
986
+ * Starts a new reasoning chunk by appending an empty string to the message's reasoning array.
987
+ * Records the start time for duration calculation.
988
+ * @param threadState - Current thread state
989
+ * @param event - Thinking text message start event
990
+ * @returns Updated thread state
991
+ */
992
+ function handleThinkingTextMessageStart(threadState, event) {
993
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
994
+ threadState = updatedThreadState;
995
+ const message = messages[messageIndex];
996
+ const existingReasoning = message.reasoning ?? [];
997
+ const updatedMessage = {
998
+ ...message,
999
+ reasoning: [...existingReasoning, ""],
1000
+ };
1001
+ // Record reasoning start time if this is the first reasoning chunk
1002
+ const reasoningStartTime = threadState.streaming.reasoningStartTime ?? event.timestamp ?? Date.now();
1003
+ return {
1004
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
1005
+ streaming: {
1006
+ ...threadState.streaming,
1007
+ reasoningStartTime,
1008
+ },
1009
+ };
1010
+ }
1011
+ /**
1012
+ * Handle THINKING_TEXT_MESSAGE_CONTENT event (will become REASONING_MESSAGE_CONTENT).
1013
+ * Appends delta text to the last reasoning chunk.
1014
+ * @param threadState - Current thread state
1015
+ * @param event - Thinking text message content event
1016
+ * @returns Updated thread state
1017
+ */
1018
+ function handleThinkingTextMessageContent(threadState, event) {
1019
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1020
+ threadState = updatedThreadState;
1021
+ const message = messages[messageIndex];
1022
+ const existingReasoning = message.reasoning ?? [];
1023
+ if (existingReasoning.length === 0) {
1024
+ // No reasoning chunk started - start one implicitly
1025
+ const updatedMessage = {
1026
+ ...message,
1027
+ reasoning: [event.delta],
1028
+ };
1029
+ return {
1030
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
1031
+ streaming: {
1032
+ ...threadState.streaming,
1033
+ reasoningStartTime: threadState.streaming.reasoningStartTime ??
1034
+ event.timestamp ??
1035
+ Date.now(),
1036
+ },
1037
+ };
1038
+ }
1039
+ // Append to the last reasoning chunk
1040
+ const updatedReasoning = [
1041
+ ...existingReasoning.slice(0, -1),
1042
+ existingReasoning[existingReasoning.length - 1] + event.delta,
1043
+ ];
1044
+ const updatedMessage = {
1045
+ ...message,
1046
+ reasoning: updatedReasoning,
1047
+ };
1048
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1049
+ }
1050
+ /**
1051
+ * Handle THINKING_TEXT_MESSAGE_END event (will become REASONING_MESSAGE_END).
1052
+ * Calculates and stores the reasoning duration.
1053
+ * @param threadState - Current thread state
1054
+ * @param event - Thinking text message end event
1055
+ * @returns Updated thread state
1056
+ */
1057
+ function handleThinkingTextMessageEnd(threadState, event) {
1058
+ const { messageIndex, messages, threadState: updatedThreadState, } = findOrCreateMessageForReasoning(threadState);
1059
+ threadState = updatedThreadState;
1060
+ const message = messages[messageIndex];
1061
+ // Calculate duration if we have a start time
1062
+ const reasoningStartTime = threadState.streaming.reasoningStartTime;
1063
+ const endTime = event.timestamp ?? Date.now();
1064
+ const reasoningDurationMS = reasoningStartTime
1065
+ ? endTime - reasoningStartTime
1066
+ : undefined;
1067
+ const updatedMessage = {
1068
+ ...message,
1069
+ reasoningDurationMS: reasoningDurationMS ?? message.reasoningDurationMS ?? undefined,
1070
+ };
1071
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
1072
+ }
1073
+ /**
1074
+ * Handle LOAD_THREAD_MESSAGES action.
1075
+ * Loads messages from API into stream state for an existing thread.
1076
+ * Deduplicates by message ID, keeping existing messages (they may have in-flight updates).
1077
+ * Sorts merged messages by createdAt to ensure chronological order.
1078
+ * @param state - Current stream state
1079
+ * @param action - Load thread messages action
1080
+ * @returns Updated stream state
1081
+ */
1082
+ function handleLoadThreadMessages(state, action) {
1083
+ const { threadId, messages, skipIfStreaming } = action;
1084
+ // Get or create thread state
1085
+ let threadState = state.threadMap[threadId];
1086
+ if (!threadState) {
1087
+ threadState = createInitialThreadState(threadId);
1088
+ }
1089
+ // Skip if streaming and skipIfStreaming is true
1090
+ if (skipIfStreaming && threadState.streaming.status === "streaming") {
1091
+ return state;
1092
+ }
1093
+ const existingMessages = threadState.thread.messages;
1094
+ // Build a set of existing message IDs for fast lookup
1095
+ const existingIds = new Set(existingMessages.map((m) => m.id));
1096
+ // Filter out messages that already exist (keep existing, add new).
1097
+ // API-loaded messages are by definition fully complete, so stamp
1098
+ // streamingState: "done" on all component content blocks. This is
1099
+ // required by downstream hooks (usePropsStreamingStatus) which check
1100
+ // streamingState === "done" to report isSuccess: true.
1101
+ const newMessages = messages
1102
+ .filter((m) => !existingIds.has(m.id))
1103
+ .map((m) => ({
1104
+ ...m,
1105
+ content: m.content.map((block) => {
1106
+ if (block.type !== "component")
1107
+ return block;
1108
+ if (block.streamingState !== undefined &&
1109
+ block.streamingState !== "done") {
1110
+ console.warn(`LOAD_THREAD_MESSAGES: component "${block.id}" has unexpected ` +
1111
+ `streamingState "${block.streamingState}". API-loaded messages ` +
1112
+ `should not have in-flight streaming state.`);
1113
+ }
1114
+ return { ...block, streamingState: "done" };
1115
+ }),
1116
+ }));
1117
+ // Merge and sort by createdAt
1118
+ const mergedMessages = [...existingMessages, ...newMessages].toSorted((a, b) => {
1119
+ // Messages without createdAt go to the end
1120
+ if (!a.createdAt && !b.createdAt)
1121
+ return 0;
1122
+ if (!a.createdAt)
1123
+ return 1;
1124
+ if (!b.createdAt)
1125
+ return -1;
1126
+ return a.createdAt.localeCompare(b.createdAt);
1127
+ });
1128
+ const updatedThreadState = {
1129
+ ...threadState,
1130
+ thread: {
1131
+ ...threadState.thread,
1132
+ messages: mergedMessages,
1133
+ updatedAt: new Date().toISOString(),
1134
+ },
1135
+ };
1136
+ return {
1137
+ ...state,
1138
+ threadMap: {
1139
+ ...state.threadMap,
1140
+ [threadId]: updatedThreadState,
1141
+ },
1142
+ };
1143
+ }
735
1144
  //# sourceMappingURL=event-accumulator.js.map