@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
@@ -1,16 +1,28 @@
1
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
1
2
  import { renderHook, act } from "@testing-library/react";
2
- import React from "react";
3
- import { useTamboClient } from "../../providers/tambo-client-provider";
4
- import { TamboRegistryContext, } from "../../providers/tambo-registry-provider";
5
- import { TamboV1StreamProvider } from "../providers/tambo-v1-stream-context";
6
- import { useTamboV1 } from "./use-tambo-v1";
3
+ import React, { useReducer } from "react";
4
+ import { useTamboClient } from "../../providers/tambo-client-provider.js";
5
+ import { TamboRegistryContext, } from "../../providers/tambo-registry-provider.js";
6
+ import { TamboV1StreamProvider } from "../providers/tambo-v1-stream-context.js";
7
+ import { streamReducer, } from "../utils/event-accumulator.js";
8
+ import { useTamboV1 } from "./use-tambo-v1.js";
7
9
  jest.mock("../../providers/tambo-client-provider", () => ({
8
10
  useTamboClient: jest.fn(),
11
+ useTamboQueryClient: jest.fn(),
9
12
  }));
13
+ import { useTamboQueryClient } from "../../providers/tambo-client-provider.js";
10
14
  describe("useTamboV1", () => {
15
+ let queryClient;
11
16
  const mockTamboClient = {
12
17
  apiKey: "",
13
- threads: {},
18
+ threads: {
19
+ messages: {
20
+ list: jest.fn().mockResolvedValue({ messages: [], hasMore: false }),
21
+ },
22
+ runs: {
23
+ delete: jest.fn().mockResolvedValue({}),
24
+ },
25
+ },
14
26
  };
15
27
  const mockRegistry = {
16
28
  componentList: {},
@@ -30,11 +42,35 @@ describe("useTamboV1", () => {
30
42
  registerResourceSource: jest.fn(),
31
43
  };
32
44
  function TestWrapper({ children }) {
33
- return (React.createElement(TamboRegistryContext.Provider, { value: mockRegistry },
34
- React.createElement(TamboV1StreamProvider, null, children)));
45
+ return (React.createElement(QueryClientProvider, { client: queryClient },
46
+ React.createElement(TamboRegistryContext.Provider, { value: mockRegistry },
47
+ React.createElement(TamboV1StreamProvider, null, children))));
48
+ }
49
+ function createWrapperWithState(state, registry = mockRegistry) {
50
+ const noopDispatch = () => { };
51
+ return function WrapperWithState({ children, }) {
52
+ return (React.createElement(QueryClientProvider, { client: queryClient },
53
+ React.createElement(TamboRegistryContext.Provider, { value: registry },
54
+ React.createElement(TamboV1StreamProvider, { state: state, dispatch: noopDispatch }, children))));
55
+ };
56
+ }
57
+ // Wrapper that uses the real reducer so state updates properly
58
+ function createWrapperWithRealReducer(initialState) {
59
+ return function WrapperWithRealReducer({ children, }) {
60
+ const [state, dispatch] = useReducer(streamReducer, initialState);
61
+ return (React.createElement(QueryClientProvider, { client: queryClient },
62
+ React.createElement(TamboRegistryContext.Provider, { value: mockRegistry },
63
+ React.createElement(TamboV1StreamProvider, { state: state, dispatch: dispatch }, children))));
64
+ };
35
65
  }
36
66
  beforeEach(() => {
67
+ queryClient = new QueryClient({
68
+ defaultOptions: {
69
+ queries: { retry: false },
70
+ },
71
+ });
37
72
  jest.mocked(useTamboClient).mockReturnValue(mockTamboClient);
73
+ jest.mocked(useTamboQueryClient).mockReturnValue(queryClient);
38
74
  jest.clearAllMocks();
39
75
  });
40
76
  it("returns client from useTamboClient", () => {
@@ -53,20 +89,23 @@ describe("useTamboV1", () => {
53
89
  expect(result.current.componentList).toBe(mockRegistry.componentList);
54
90
  expect(result.current.toolRegistry).toBe(mockRegistry.toolRegistry);
55
91
  });
56
- it("returns undefined thread when no threadId provided", () => {
92
+ it("returns placeholder thread when no threadId provided", () => {
57
93
  const { result } = renderHook(() => useTamboV1(), {
58
94
  wrapper: TestWrapper,
59
95
  });
60
- expect(result.current.thread).toBeUndefined();
96
+ // Default state has placeholder thread for optimistic UI
97
+ expect(result.current.thread).toBeDefined();
98
+ expect(result.current.thread?.thread.id).toBe("placeholder");
61
99
  expect(result.current.messages).toEqual([]);
62
100
  });
63
- it("returns thread state when threadId provided", () => {
64
- const { result } = renderHook(() => useTamboV1("thread_123"), {
101
+ it("returns thread state when switched to a thread", () => {
102
+ const { result } = renderHook(() => useTamboV1(), {
65
103
  wrapper: TestWrapper,
66
104
  });
67
- // Initialize thread first
105
+ // Initialize and switch to thread
68
106
  act(() => {
69
107
  result.current.initThread("thread_123");
108
+ result.current.switchThread("thread_123");
70
109
  });
71
110
  expect(result.current.thread).toBeDefined();
72
111
  expect(result.current.thread?.thread.id).toBe("thread_123");
@@ -82,12 +121,13 @@ describe("useTamboV1", () => {
82
121
  expect(result.current.isWaiting).toBe(false);
83
122
  });
84
123
  it("returns thread streaming state when thread loaded", () => {
85
- const { result } = renderHook(() => useTamboV1("thread_123"), {
124
+ const { result } = renderHook(() => useTamboV1(), {
86
125
  wrapper: TestWrapper,
87
126
  });
88
- // Initialize thread first
127
+ // Initialize and switch to thread
89
128
  act(() => {
90
129
  result.current.initThread("thread_123");
130
+ result.current.switchThread("thread_123");
91
131
  });
92
132
  expect(result.current.streamingState.status).toBe("idle");
93
133
  expect(result.current.isIdle).toBe(true);
@@ -112,9 +152,10 @@ describe("useTamboV1", () => {
112
152
  const { result } = renderHook(() => useTamboV1(), {
113
153
  wrapper: TestWrapper,
114
154
  });
115
- // Initially no current thread
116
- expect(result.current.currentThreadId).toBeNull();
117
- expect(result.current.thread).toBeUndefined();
155
+ // Initially has placeholder thread for optimistic UI
156
+ expect(result.current.currentThreadId).toBe("placeholder");
157
+ expect(result.current.thread).toBeDefined();
158
+ expect(result.current.thread?.thread.id).toBe("placeholder");
118
159
  // Initialize a new thread
119
160
  act(() => {
120
161
  result.current.initThread("new_thread_1");
@@ -133,7 +174,7 @@ describe("useTamboV1", () => {
133
174
  act(() => {
134
175
  newThreadId = result.current.startNewThread();
135
176
  });
136
- expect(newThreadId).toMatch(/^temp_/);
177
+ expect(newThreadId).toBe("placeholder");
137
178
  expect(result.current.currentThreadId).toBe(newThreadId);
138
179
  expect(result.current.thread).toBeDefined();
139
180
  });
@@ -150,5 +191,807 @@ describe("useTamboV1", () => {
150
191
  expect(result.current.currentThreadId).toBe("thread_123");
151
192
  expect(result.current.thread?.thread.id).toBe("thread_123");
152
193
  });
194
+ describe("component content transformation", () => {
195
+ const createComponentContent = (id, name, props) => ({
196
+ type: "component",
197
+ id,
198
+ name,
199
+ props,
200
+ streamingState: "done",
201
+ });
202
+ it("adds renderedComponent to component content blocks", () => {
203
+ const state = {
204
+ threadMap: {
205
+ thread_123: {
206
+ thread: {
207
+ id: "thread_123",
208
+ messages: [
209
+ {
210
+ id: "msg_1",
211
+ role: "assistant",
212
+ content: [
213
+ createComponentContent("comp_1", "TestComponent", {
214
+ title: "Hello",
215
+ }),
216
+ ],
217
+ createdAt: new Date().toISOString(),
218
+ },
219
+ ],
220
+ status: "idle",
221
+ createdAt: new Date().toISOString(),
222
+ updatedAt: new Date().toISOString(),
223
+ lastRunCancelled: false,
224
+ },
225
+ streaming: { status: "idle" },
226
+ accumulatingToolArgs: new Map(),
227
+ },
228
+ },
229
+ currentThreadId: "thread_123",
230
+ };
231
+ const { result } = renderHook(() => useTamboV1(), {
232
+ wrapper: createWrapperWithState(state),
233
+ });
234
+ expect(result.current.messages).toHaveLength(1);
235
+ const content = result.current.messages[0].content[0];
236
+ expect(content.type).toBe("component");
237
+ expect(content.renderedComponent).toBeDefined();
238
+ });
239
+ it("preserves non-component content blocks unchanged", () => {
240
+ const state = {
241
+ threadMap: {
242
+ thread_123: {
243
+ thread: {
244
+ id: "thread_123",
245
+ messages: [
246
+ {
247
+ id: "msg_1",
248
+ role: "assistant",
249
+ content: [
250
+ { type: "text", text: "Hello world" },
251
+ createComponentContent("comp_1", "TestComponent", {
252
+ title: "Hi",
253
+ }),
254
+ ],
255
+ createdAt: new Date().toISOString(),
256
+ },
257
+ ],
258
+ status: "idle",
259
+ createdAt: new Date().toISOString(),
260
+ updatedAt: new Date().toISOString(),
261
+ lastRunCancelled: false,
262
+ },
263
+ streaming: { status: "idle" },
264
+ accumulatingToolArgs: new Map(),
265
+ },
266
+ },
267
+ currentThreadId: "thread_123",
268
+ };
269
+ const { result } = renderHook(() => useTamboV1(), {
270
+ wrapper: createWrapperWithState(state),
271
+ });
272
+ expect(result.current.messages).toHaveLength(1);
273
+ const textContent = result.current.messages[0].content[0];
274
+ expect(textContent.type).toBe("text");
275
+ expect(textContent).toEqual({ type: "text", text: "Hello world" });
276
+ const componentContent = result.current.messages[0].content[1];
277
+ expect(componentContent.type).toBe("component");
278
+ expect(componentContent.renderedComponent).toBeDefined();
279
+ });
280
+ it("caches rendered components and returns same reference when props unchanged", () => {
281
+ const state = {
282
+ threadMap: {
283
+ thread_123: {
284
+ thread: {
285
+ id: "thread_123",
286
+ messages: [
287
+ {
288
+ id: "msg_1",
289
+ role: "assistant",
290
+ content: [
291
+ createComponentContent("comp_1", "TestComponent", {
292
+ title: "Hello",
293
+ }),
294
+ ],
295
+ createdAt: new Date().toISOString(),
296
+ },
297
+ ],
298
+ status: "idle",
299
+ createdAt: new Date().toISOString(),
300
+ updatedAt: new Date().toISOString(),
301
+ lastRunCancelled: false,
302
+ },
303
+ streaming: { status: "idle" },
304
+ accumulatingToolArgs: new Map(),
305
+ },
306
+ },
307
+ currentThreadId: "thread_123",
308
+ };
309
+ const { result, rerender } = renderHook(() => useTamboV1(), {
310
+ wrapper: createWrapperWithState(state),
311
+ });
312
+ const firstRender = result.current.messages[0].content[0].renderedComponent;
313
+ // Re-render with same state
314
+ rerender();
315
+ const secondRender = result.current.messages[0].content[0].renderedComponent;
316
+ // Should return the same cached element reference
317
+ expect(secondRender).toBe(firstRender);
318
+ });
319
+ it("handles empty props on components", () => {
320
+ const state = {
321
+ threadMap: {
322
+ thread_123: {
323
+ thread: {
324
+ id: "thread_123",
325
+ messages: [
326
+ {
327
+ id: "msg_1",
328
+ role: "assistant",
329
+ content: [
330
+ createComponentContent("comp_1", "TestComponent", {}),
331
+ ],
332
+ createdAt: new Date().toISOString(),
333
+ },
334
+ ],
335
+ status: "idle",
336
+ createdAt: new Date().toISOString(),
337
+ updatedAt: new Date().toISOString(),
338
+ lastRunCancelled: false,
339
+ },
340
+ streaming: { status: "idle" },
341
+ accumulatingToolArgs: new Map(),
342
+ },
343
+ },
344
+ currentThreadId: "thread_123",
345
+ };
346
+ const { result } = renderHook(() => useTamboV1(), {
347
+ wrapper: createWrapperWithState(state),
348
+ });
349
+ const content = result.current.messages[0].content[0];
350
+ expect(content.type).toBe("component");
351
+ expect(content.renderedComponent).toBeDefined();
352
+ });
353
+ it("handles undefined props on components", () => {
354
+ const state = {
355
+ threadMap: {
356
+ thread_123: {
357
+ thread: {
358
+ id: "thread_123",
359
+ messages: [
360
+ {
361
+ id: "msg_1",
362
+ role: "assistant",
363
+ content: [
364
+ {
365
+ type: "component",
366
+ id: "comp_1",
367
+ name: "TestComponent",
368
+ props: undefined,
369
+ streamingState: "done",
370
+ },
371
+ ],
372
+ createdAt: new Date().toISOString(),
373
+ },
374
+ ],
375
+ status: "idle",
376
+ createdAt: new Date().toISOString(),
377
+ updatedAt: new Date().toISOString(),
378
+ lastRunCancelled: false,
379
+ },
380
+ streaming: { status: "idle" },
381
+ accumulatingToolArgs: new Map(),
382
+ },
383
+ },
384
+ currentThreadId: "thread_123",
385
+ };
386
+ const { result } = renderHook(() => useTamboV1(), {
387
+ wrapper: createWrapperWithState(state),
388
+ });
389
+ const content = result.current.messages[0].content[0];
390
+ expect(content.type).toBe("component");
391
+ expect(content.renderedComponent).toBeDefined();
392
+ });
393
+ it("handles multiple component content blocks in same message", () => {
394
+ const state = {
395
+ threadMap: {
396
+ thread_123: {
397
+ thread: {
398
+ id: "thread_123",
399
+ messages: [
400
+ {
401
+ id: "msg_1",
402
+ role: "assistant",
403
+ content: [
404
+ createComponentContent("comp_1", "ComponentA", {
405
+ value: 1,
406
+ }),
407
+ createComponentContent("comp_2", "ComponentB", {
408
+ value: 2,
409
+ }),
410
+ createComponentContent("comp_3", "ComponentC", {
411
+ value: 3,
412
+ }),
413
+ ],
414
+ createdAt: new Date().toISOString(),
415
+ },
416
+ ],
417
+ status: "idle",
418
+ createdAt: new Date().toISOString(),
419
+ updatedAt: new Date().toISOString(),
420
+ lastRunCancelled: false,
421
+ },
422
+ streaming: { status: "idle" },
423
+ accumulatingToolArgs: new Map(),
424
+ },
425
+ },
426
+ currentThreadId: "thread_123",
427
+ };
428
+ const { result } = renderHook(() => useTamboV1(), {
429
+ wrapper: createWrapperWithState(state),
430
+ });
431
+ expect(result.current.messages[0].content).toHaveLength(3);
432
+ result.current.messages[0].content.forEach((content) => {
433
+ expect(content.type).toBe("component");
434
+ expect(content.renderedComponent).toBeDefined();
435
+ });
436
+ });
437
+ it("uses currentThreadId from stream state", () => {
438
+ const state = {
439
+ threadMap: {
440
+ placeholder: {
441
+ thread: {
442
+ id: "placeholder",
443
+ messages: [
444
+ {
445
+ id: "msg_1",
446
+ role: "assistant",
447
+ content: [
448
+ createComponentContent("comp_1", "TestComponent", {
449
+ title: "Hello",
450
+ }),
451
+ ],
452
+ createdAt: new Date().toISOString(),
453
+ },
454
+ ],
455
+ status: "idle",
456
+ createdAt: new Date().toISOString(),
457
+ updatedAt: new Date().toISOString(),
458
+ lastRunCancelled: false,
459
+ },
460
+ streaming: { status: "idle" },
461
+ accumulatingToolArgs: new Map(),
462
+ },
463
+ },
464
+ currentThreadId: "placeholder",
465
+ };
466
+ // No explicit threadId - uses currentThreadId from state
467
+ const { result } = renderHook(() => useTamboV1(), {
468
+ wrapper: createWrapperWithState(state),
469
+ });
470
+ // Component should render using the placeholder thread
471
+ const content = result.current.messages[0].content[0];
472
+ expect(content.type).toBe("component");
473
+ expect(content.renderedComponent).toBeDefined();
474
+ });
475
+ });
476
+ describe("tool_use content transformation", () => {
477
+ it("adds computed properties to tool_use content", () => {
478
+ const state = {
479
+ threadMap: {
480
+ thread_123: {
481
+ thread: {
482
+ id: "thread_123",
483
+ messages: [
484
+ {
485
+ id: "msg_1",
486
+ role: "assistant",
487
+ content: [
488
+ {
489
+ type: "tool_use",
490
+ id: "tool_1",
491
+ name: "getWeather",
492
+ input: { location: "NYC" },
493
+ },
494
+ ],
495
+ createdAt: new Date().toISOString(),
496
+ },
497
+ ],
498
+ status: "idle",
499
+ createdAt: new Date().toISOString(),
500
+ updatedAt: new Date().toISOString(),
501
+ lastRunCancelled: false,
502
+ },
503
+ streaming: { status: "idle" },
504
+ accumulatingToolArgs: new Map(),
505
+ },
506
+ },
507
+ currentThreadId: "thread_123",
508
+ };
509
+ const { result } = renderHook(() => useTamboV1(), {
510
+ wrapper: createWrapperWithState(state),
511
+ });
512
+ const content = result.current.messages[0].content[0];
513
+ expect(content.type).toBe("tool_use");
514
+ expect(content.hasCompleted).toBe(false);
515
+ expect(content.statusMessage).toBe("Calling getWeather");
516
+ expect(content.tamboDisplayProps).toBeDefined();
517
+ });
518
+ it("sets hasCompleted to true when matching tool_result exists", () => {
519
+ const state = {
520
+ threadMap: {
521
+ thread_123: {
522
+ thread: {
523
+ id: "thread_123",
524
+ messages: [
525
+ {
526
+ id: "msg_1",
527
+ role: "assistant",
528
+ content: [
529
+ {
530
+ type: "tool_use",
531
+ id: "tool_1",
532
+ name: "getWeather",
533
+ input: { location: "NYC" },
534
+ },
535
+ ],
536
+ createdAt: new Date().toISOString(),
537
+ },
538
+ {
539
+ id: "msg_2",
540
+ role: "user",
541
+ content: [
542
+ {
543
+ type: "tool_result",
544
+ toolUseId: "tool_1",
545
+ content: [{ type: "text", text: "Sunny" }],
546
+ },
547
+ ],
548
+ createdAt: new Date().toISOString(),
549
+ },
550
+ ],
551
+ status: "idle",
552
+ createdAt: new Date().toISOString(),
553
+ updatedAt: new Date().toISOString(),
554
+ lastRunCancelled: false,
555
+ },
556
+ streaming: { status: "idle" },
557
+ accumulatingToolArgs: new Map(),
558
+ },
559
+ },
560
+ currentThreadId: "thread_123",
561
+ };
562
+ const { result } = renderHook(() => useTamboV1(), {
563
+ wrapper: createWrapperWithState(state),
564
+ });
565
+ const content = result.current.messages[0].content[0];
566
+ expect(content.hasCompleted).toBe(true);
567
+ expect(content.statusMessage).toBe("Called getWeather");
568
+ });
569
+ it("uses _tambo_statusMessage when tool is in progress", () => {
570
+ const state = {
571
+ threadMap: {
572
+ thread_123: {
573
+ thread: {
574
+ id: "thread_123",
575
+ messages: [
576
+ {
577
+ id: "msg_1",
578
+ role: "assistant",
579
+ content: [
580
+ {
581
+ type: "tool_use",
582
+ id: "tool_1",
583
+ name: "getWeather",
584
+ input: {
585
+ location: "NYC",
586
+ _tambo_statusMessage: "Fetching weather for NYC...",
587
+ },
588
+ },
589
+ ],
590
+ createdAt: new Date().toISOString(),
591
+ },
592
+ ],
593
+ status: "idle",
594
+ createdAt: new Date().toISOString(),
595
+ updatedAt: new Date().toISOString(),
596
+ lastRunCancelled: false,
597
+ },
598
+ streaming: { status: "idle" },
599
+ accumulatingToolArgs: new Map(),
600
+ },
601
+ },
602
+ currentThreadId: "thread_123",
603
+ };
604
+ const { result } = renderHook(() => useTamboV1(), {
605
+ wrapper: createWrapperWithState(state),
606
+ });
607
+ const content = result.current.messages[0].content[0];
608
+ expect(content.statusMessage).toBe("Fetching weather for NYC...");
609
+ expect(content.tamboDisplayProps?._tambo_statusMessage).toBe("Fetching weather for NYC...");
610
+ });
611
+ it("uses _tambo_completionStatusMessage when tool is completed", () => {
612
+ const state = {
613
+ threadMap: {
614
+ thread_123: {
615
+ thread: {
616
+ id: "thread_123",
617
+ messages: [
618
+ {
619
+ id: "msg_1",
620
+ role: "assistant",
621
+ content: [
622
+ {
623
+ type: "tool_use",
624
+ id: "tool_1",
625
+ name: "getWeather",
626
+ input: {
627
+ location: "NYC",
628
+ _tambo_statusMessage: "Fetching weather...",
629
+ _tambo_completionStatusMessage: "Got weather for NYC",
630
+ },
631
+ },
632
+ ],
633
+ createdAt: new Date().toISOString(),
634
+ },
635
+ {
636
+ id: "msg_2",
637
+ role: "user",
638
+ content: [
639
+ {
640
+ type: "tool_result",
641
+ toolUseId: "tool_1",
642
+ content: [{ type: "text", text: "Sunny" }],
643
+ },
644
+ ],
645
+ createdAt: new Date().toISOString(),
646
+ },
647
+ ],
648
+ status: "idle",
649
+ createdAt: new Date().toISOString(),
650
+ updatedAt: new Date().toISOString(),
651
+ lastRunCancelled: false,
652
+ },
653
+ streaming: { status: "idle" },
654
+ accumulatingToolArgs: new Map(),
655
+ },
656
+ },
657
+ currentThreadId: "thread_123",
658
+ };
659
+ const { result } = renderHook(() => useTamboV1(), {
660
+ wrapper: createWrapperWithState(state),
661
+ });
662
+ const content = result.current.messages[0].content[0];
663
+ expect(content.hasCompleted).toBe(true);
664
+ expect(content.statusMessage).toBe("Got weather for NYC");
665
+ });
666
+ it("filters _tambo_* properties from input", () => {
667
+ const state = {
668
+ threadMap: {
669
+ thread_123: {
670
+ thread: {
671
+ id: "thread_123",
672
+ messages: [
673
+ {
674
+ id: "msg_1",
675
+ role: "assistant",
676
+ content: [
677
+ {
678
+ type: "tool_use",
679
+ id: "tool_1",
680
+ name: "getWeather",
681
+ input: {
682
+ location: "NYC",
683
+ units: "celsius",
684
+ _tambo_statusMessage: "Fetching...",
685
+ _tambo_completionStatusMessage: "Done",
686
+ _tambo_displayMessage: "Weather lookup",
687
+ },
688
+ },
689
+ ],
690
+ createdAt: new Date().toISOString(),
691
+ },
692
+ ],
693
+ status: "idle",
694
+ createdAt: new Date().toISOString(),
695
+ updatedAt: new Date().toISOString(),
696
+ lastRunCancelled: false,
697
+ },
698
+ streaming: { status: "idle" },
699
+ accumulatingToolArgs: new Map(),
700
+ },
701
+ },
702
+ currentThreadId: "thread_123",
703
+ };
704
+ const { result } = renderHook(() => useTamboV1(), {
705
+ wrapper: createWrapperWithState(state),
706
+ });
707
+ const content = result.current.messages[0].content[0];
708
+ // Input should only have non-_tambo_ properties
709
+ expect(content.input).toEqual({ location: "NYC", units: "celsius" });
710
+ expect(content.input._tambo_statusMessage).toBeUndefined();
711
+ expect(content.input._tambo_completionStatusMessage).toBeUndefined();
712
+ expect(content.input._tambo_displayMessage).toBeUndefined();
713
+ });
714
+ it("handles tool_use with empty input", () => {
715
+ const state = {
716
+ threadMap: {
717
+ thread_123: {
718
+ thread: {
719
+ id: "thread_123",
720
+ messages: [
721
+ {
722
+ id: "msg_1",
723
+ role: "assistant",
724
+ content: [
725
+ {
726
+ type: "tool_use",
727
+ id: "tool_1",
728
+ name: "getCurrentTime",
729
+ input: {},
730
+ },
731
+ ],
732
+ createdAt: new Date().toISOString(),
733
+ },
734
+ ],
735
+ status: "idle",
736
+ createdAt: new Date().toISOString(),
737
+ updatedAt: new Date().toISOString(),
738
+ lastRunCancelled: false,
739
+ },
740
+ streaming: { status: "idle" },
741
+ accumulatingToolArgs: new Map(),
742
+ },
743
+ },
744
+ currentThreadId: "thread_123",
745
+ };
746
+ const { result } = renderHook(() => useTamboV1(), {
747
+ wrapper: createWrapperWithState(state),
748
+ });
749
+ const content = result.current.messages[0].content[0];
750
+ expect(content.input).toEqual({});
751
+ expect(content.hasCompleted).toBe(false);
752
+ expect(content.statusMessage).toBe("Calling getCurrentTime");
753
+ });
754
+ it("handles tool_use with undefined input", () => {
755
+ const state = {
756
+ threadMap: {
757
+ thread_123: {
758
+ thread: {
759
+ id: "thread_123",
760
+ messages: [
761
+ {
762
+ id: "msg_1",
763
+ role: "assistant",
764
+ content: [
765
+ {
766
+ type: "tool_use",
767
+ id: "tool_1",
768
+ name: "getCurrentTime",
769
+ input: undefined,
770
+ },
771
+ ],
772
+ createdAt: new Date().toISOString(),
773
+ },
774
+ ],
775
+ status: "idle",
776
+ createdAt: new Date().toISOString(),
777
+ updatedAt: new Date().toISOString(),
778
+ lastRunCancelled: false,
779
+ },
780
+ streaming: { status: "idle" },
781
+ accumulatingToolArgs: new Map(),
782
+ },
783
+ },
784
+ currentThreadId: "thread_123",
785
+ };
786
+ const { result } = renderHook(() => useTamboV1(), {
787
+ wrapper: createWrapperWithState(state),
788
+ });
789
+ const content = result.current.messages[0].content[0];
790
+ expect(content.input).toEqual({});
791
+ expect(content.hasCompleted).toBe(false);
792
+ });
793
+ it("handles multiple tool_use blocks with different completion states", () => {
794
+ const state = {
795
+ threadMap: {
796
+ thread_123: {
797
+ thread: {
798
+ id: "thread_123",
799
+ messages: [
800
+ {
801
+ id: "msg_1",
802
+ role: "assistant",
803
+ content: [
804
+ {
805
+ type: "tool_use",
806
+ id: "tool_1",
807
+ name: "getWeather",
808
+ input: { location: "NYC" },
809
+ },
810
+ {
811
+ type: "tool_use",
812
+ id: "tool_2",
813
+ name: "getTime",
814
+ input: { timezone: "EST" },
815
+ },
816
+ ],
817
+ createdAt: new Date().toISOString(),
818
+ },
819
+ {
820
+ id: "msg_2",
821
+ role: "user",
822
+ content: [
823
+ {
824
+ type: "tool_result",
825
+ toolUseId: "tool_1",
826
+ content: [{ type: "text", text: "Sunny" }],
827
+ },
828
+ // tool_2 has no result yet
829
+ ],
830
+ createdAt: new Date().toISOString(),
831
+ },
832
+ ],
833
+ status: "idle",
834
+ createdAt: new Date().toISOString(),
835
+ updatedAt: new Date().toISOString(),
836
+ lastRunCancelled: false,
837
+ },
838
+ streaming: { status: "idle" },
839
+ accumulatingToolArgs: new Map(),
840
+ },
841
+ },
842
+ currentThreadId: "thread_123",
843
+ };
844
+ const { result } = renderHook(() => useTamboV1(), {
845
+ wrapper: createWrapperWithState(state),
846
+ });
847
+ const tool1 = result.current.messages[0].content[0];
848
+ const tool2 = result.current.messages[0].content[1];
849
+ expect(tool1.hasCompleted).toBe(true);
850
+ expect(tool1.statusMessage).toBe("Called getWeather");
851
+ expect(tool2.hasCompleted).toBe(false);
852
+ expect(tool2.statusMessage).toBe("Calling getTime");
853
+ });
854
+ });
855
+ describe("cancelRun", () => {
856
+ it("sets thread to idle and lastRunCancelled to true when cancelled", async () => {
857
+ const initialState = {
858
+ threadMap: {
859
+ thread_123: {
860
+ thread: {
861
+ id: "thread_123",
862
+ messages: [],
863
+ status: "streaming",
864
+ createdAt: new Date().toISOString(),
865
+ updatedAt: new Date().toISOString(),
866
+ lastRunCancelled: false,
867
+ },
868
+ streaming: { status: "streaming", runId: "run_456" },
869
+ accumulatingToolArgs: new Map(),
870
+ },
871
+ },
872
+ currentThreadId: "thread_123",
873
+ };
874
+ const { result } = renderHook(() => useTamboV1(), {
875
+ wrapper: createWrapperWithRealReducer(initialState),
876
+ });
877
+ // Before cancel: streaming and lastRunCancelled is false
878
+ expect(result.current.isStreaming).toBe(true);
879
+ expect(result.current.isIdle).toBe(false);
880
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(false);
881
+ await act(async () => {
882
+ await result.current.cancelRun();
883
+ });
884
+ // After cancel: idle and lastRunCancelled is true
885
+ expect(result.current.isStreaming).toBe(false);
886
+ expect(result.current.isIdle).toBe(true);
887
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(true);
888
+ // Verify API was called to cancel the run
889
+ expect(mockTamboClient.threads.runs.delete).toHaveBeenCalledWith("run_456", { threadId: "thread_123" });
890
+ });
891
+ it("is a no-op when there is no active run", async () => {
892
+ const initialState = {
893
+ threadMap: {
894
+ thread_123: {
895
+ thread: {
896
+ id: "thread_123",
897
+ messages: [],
898
+ status: "idle",
899
+ createdAt: new Date().toISOString(),
900
+ updatedAt: new Date().toISOString(),
901
+ lastRunCancelled: false,
902
+ },
903
+ streaming: { status: "idle" }, // No runId
904
+ accumulatingToolArgs: new Map(),
905
+ },
906
+ },
907
+ currentThreadId: "thread_123",
908
+ };
909
+ const { result } = renderHook(() => useTamboV1(), {
910
+ wrapper: createWrapperWithRealReducer(initialState),
911
+ });
912
+ // Idle before
913
+ expect(result.current.isIdle).toBe(true);
914
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(false);
915
+ await act(async () => {
916
+ await result.current.cancelRun();
917
+ });
918
+ // Still idle, lastRunCancelled unchanged
919
+ expect(result.current.isIdle).toBe(true);
920
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(false);
921
+ // API should not have been called
922
+ expect(mockTamboClient.threads.runs.delete).not.toHaveBeenCalled();
923
+ });
924
+ it("is a no-op when on a placeholder thread", async () => {
925
+ const initialState = {
926
+ threadMap: {
927
+ placeholder: {
928
+ thread: {
929
+ id: "placeholder",
930
+ messages: [],
931
+ status: "streaming",
932
+ createdAt: new Date().toISOString(),
933
+ updatedAt: new Date().toISOString(),
934
+ lastRunCancelled: false,
935
+ },
936
+ streaming: { status: "streaming", runId: "run_123" },
937
+ accumulatingToolArgs: new Map(),
938
+ },
939
+ },
940
+ currentThreadId: "placeholder",
941
+ };
942
+ const { result } = renderHook(() => useTamboV1(), {
943
+ wrapper: createWrapperWithRealReducer(initialState),
944
+ });
945
+ // Before: streaming on placeholder
946
+ expect(result.current.isStreaming).toBe(true);
947
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(false);
948
+ await act(async () => {
949
+ await result.current.cancelRun();
950
+ });
951
+ // After: state should be unchanged (placeholder threads are skipped)
952
+ expect(result.current.isStreaming).toBe(true);
953
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(false);
954
+ // API should not have been called for placeholder threads
955
+ expect(mockTamboClient.threads.runs.delete).not.toHaveBeenCalled();
956
+ });
957
+ it("still updates local state even if API call fails", async () => {
958
+ const consoleWarnSpy = jest
959
+ .spyOn(console, "warn")
960
+ .mockImplementation(() => { });
961
+ // Make the API call fail
962
+ jest
963
+ .mocked(mockTamboClient.threads.runs.delete)
964
+ .mockRejectedValueOnce(new Error("Network error"));
965
+ const initialState = {
966
+ threadMap: {
967
+ thread_123: {
968
+ thread: {
969
+ id: "thread_123",
970
+ messages: [],
971
+ status: "streaming",
972
+ createdAt: new Date().toISOString(),
973
+ updatedAt: new Date().toISOString(),
974
+ lastRunCancelled: false,
975
+ },
976
+ streaming: { status: "streaming", runId: "run_456" },
977
+ accumulatingToolArgs: new Map(),
978
+ },
979
+ },
980
+ currentThreadId: "thread_123",
981
+ };
982
+ const { result } = renderHook(() => useTamboV1(), {
983
+ wrapper: createWrapperWithRealReducer(initialState),
984
+ });
985
+ await act(async () => {
986
+ await result.current.cancelRun();
987
+ });
988
+ // Local state should still be updated (optimistic update)
989
+ expect(result.current.isIdle).toBe(true);
990
+ expect(result.current.thread?.thread.lastRunCancelled).toBe(true);
991
+ // Warning should have been logged
992
+ expect(consoleWarnSpy).toHaveBeenCalledWith("Failed to cancel run on server:", expect.any(Error));
993
+ consoleWarnSpy.mockRestore();
994
+ });
995
+ });
153
996
  });
154
997
  //# sourceMappingURL=use-tambo-v1.test.js.map