@tambo-ai/react 0.67.1 → 0.69.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 (424) hide show
  1. package/README.md +3 -5
  2. package/dist/context-helpers/context-helpers.test.js +16 -4
  3. package/dist/context-helpers/context-helpers.test.js.map +1 -1
  4. package/dist/context-helpers/current-interactables-context-helper.d.ts +2 -2
  5. package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  6. package/dist/context-helpers/current-interactables-context-helper.js +31 -12
  7. package/dist/context-helpers/current-interactables-context-helper.js.map +1 -1
  8. package/dist/context-helpers/registry.d.ts +2 -2
  9. package/dist/context-helpers/registry.d.ts.map +1 -1
  10. package/dist/context-helpers/registry.js.map +1 -1
  11. package/dist/context-helpers/types.d.ts +2 -2
  12. package/dist/context-helpers/types.d.ts.map +1 -1
  13. package/dist/context-helpers/types.js.map +1 -1
  14. package/dist/hoc/with-tambo-interactable.d.ts +50 -4
  15. package/dist/hoc/with-tambo-interactable.d.ts.map +1 -1
  16. package/dist/hoc/with-tambo-interactable.js +20 -5
  17. package/dist/hoc/with-tambo-interactable.js.map +1 -1
  18. package/dist/hooks/use-component-state.d.ts +3 -8
  19. package/dist/hooks/use-component-state.d.ts.map +1 -1
  20. package/dist/hooks/use-component-state.js +8 -0
  21. package/dist/hooks/use-component-state.js.map +1 -1
  22. package/dist/hooks/use-component-state.test.js +37 -0
  23. package/dist/hooks/use-component-state.test.js.map +1 -1
  24. package/dist/hooks/use-message-images.test.js +174 -37
  25. package/dist/hooks/use-message-images.test.js.map +1 -1
  26. package/dist/hooks/use-tambo-threads.js +1 -1
  27. package/dist/hooks/use-tambo-threads.js.map +1 -1
  28. package/dist/hooks/use-tambo-voice.d.ts +1 -1
  29. package/dist/hooks/use-tambo-voice.js +1 -1
  30. package/dist/hooks/use-tambo-voice.js.map +1 -1
  31. package/dist/hooks/use-tambo-voice.test.d.ts +2 -0
  32. package/dist/hooks/use-tambo-voice.test.d.ts.map +1 -0
  33. package/dist/hooks/use-tambo-voice.test.js +239 -0
  34. package/dist/hooks/use-tambo-voice.test.js.map +1 -0
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/mcp/elicitation.d.ts.map +1 -1
  39. package/dist/mcp/elicitation.js +12 -0
  40. package/dist/mcp/elicitation.js.map +1 -1
  41. package/dist/mcp/elicitation.test.js +8 -1
  42. package/dist/mcp/elicitation.test.js.map +1 -1
  43. package/dist/mcp/mcp-client.d.ts +6 -10
  44. package/dist/mcp/mcp-client.d.ts.map +1 -1
  45. package/dist/mcp/mcp-client.js.map +1 -1
  46. package/dist/mcp/mcp-constants.d.ts +19 -0
  47. package/dist/mcp/mcp-constants.d.ts.map +1 -0
  48. package/dist/mcp/mcp-constants.js +21 -0
  49. package/dist/mcp/mcp-constants.js.map +1 -0
  50. package/dist/mcp/mcp-hooks.d.ts +21 -40
  51. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  52. package/dist/mcp/mcp-hooks.js +130 -39
  53. package/dist/mcp/mcp-hooks.js.map +1 -1
  54. package/dist/mcp/mcp-hooks.test.js +431 -5
  55. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  56. package/dist/mcp/tambo-mcp-provider.d.ts +7 -0
  57. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  58. package/dist/mcp/tambo-mcp-provider.js +205 -155
  59. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  60. package/dist/mcp/tambo-mcp-provider.test.js +37 -0
  61. package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
  62. package/dist/model/component-metadata.d.ts +54 -21
  63. package/dist/model/component-metadata.d.ts.map +1 -1
  64. package/dist/model/component-metadata.js.map +1 -1
  65. package/dist/model/tambo-interactable.d.ts +13 -5
  66. package/dist/model/tambo-interactable.d.ts.map +1 -1
  67. package/dist/model/tambo-interactable.js.map +1 -1
  68. package/dist/providers/__tests__/thread-input-resource-resolution.test.d.ts +2 -0
  69. package/dist/providers/__tests__/thread-input-resource-resolution.test.d.ts.map +1 -0
  70. package/dist/providers/__tests__/thread-input-resource-resolution.test.js +592 -0
  71. package/dist/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -0
  72. package/dist/providers/index.d.ts +1 -1
  73. package/dist/providers/index.d.ts.map +1 -1
  74. package/dist/providers/index.js.map +1 -1
  75. package/dist/providers/tambo-client-provider.d.ts +8 -0
  76. package/dist/providers/tambo-client-provider.d.ts.map +1 -1
  77. package/dist/providers/tambo-client-provider.js +10 -11
  78. package/dist/providers/tambo-client-provider.js.map +1 -1
  79. package/dist/providers/tambo-client-provider.test.d.ts +2 -0
  80. package/dist/providers/tambo-client-provider.test.d.ts.map +1 -0
  81. package/dist/providers/tambo-client-provider.test.js +208 -0
  82. package/dist/providers/tambo-client-provider.test.js.map +1 -0
  83. package/dist/providers/tambo-context-attachment-provider.d.ts +34 -92
  84. package/dist/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  85. package/dist/providers/tambo-context-attachment-provider.js +62 -105
  86. package/dist/providers/tambo-context-attachment-provider.js.map +1 -1
  87. package/dist/providers/tambo-context-attachment-provider.test.js +229 -463
  88. package/dist/providers/tambo-context-attachment-provider.test.js.map +1 -1
  89. package/dist/providers/tambo-interactable-provider-partial-updates.test.js +22 -21
  90. package/dist/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  91. package/dist/providers/tambo-interactable-provider.d.ts +5 -2
  92. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  93. package/dist/providers/tambo-interactable-provider.js +126 -17
  94. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  95. package/dist/providers/tambo-interactable-provider.test.js +242 -0
  96. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  97. package/dist/providers/tambo-interactables-additional-context.test.js +2 -5
  98. package/dist/providers/tambo-interactables-additional-context.test.js.map +1 -1
  99. package/dist/providers/tambo-provider.d.ts +2 -3
  100. package/dist/providers/tambo-provider.d.ts.map +1 -1
  101. package/dist/providers/tambo-provider.js +6 -5
  102. package/dist/providers/tambo-provider.js.map +1 -1
  103. package/dist/providers/tambo-registry-provider.test.js +16 -0
  104. package/dist/providers/tambo-registry-provider.test.js.map +1 -1
  105. package/dist/providers/tambo-registry-schema-compat.test.js +31 -0
  106. package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -1
  107. package/dist/providers/tambo-thread-input-provider.d.ts +1 -1
  108. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  109. package/dist/providers/tambo-thread-input-provider.js +26 -4
  110. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  111. package/dist/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  112. package/dist/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  113. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  114. package/dist/providers/tambo-thread-provider.js +53 -42
  115. package/dist/providers/tambo-thread-provider.js.map +1 -1
  116. package/dist/providers/tambo-thread-provider.test.js +368 -262
  117. package/dist/providers/tambo-thread-provider.test.js.map +1 -1
  118. package/dist/schema/index.d.ts +1 -1
  119. package/dist/schema/index.d.ts.map +1 -1
  120. package/dist/schema/index.js +2 -1
  121. package/dist/schema/index.js.map +1 -1
  122. package/dist/schema/json-schema.d.ts +7 -0
  123. package/dist/schema/json-schema.d.ts.map +1 -1
  124. package/dist/schema/json-schema.js +40 -29
  125. package/dist/schema/json-schema.js.map +1 -1
  126. package/dist/schema/json-schema.test.d.ts +2 -0
  127. package/dist/schema/json-schema.test.d.ts.map +1 -0
  128. package/dist/schema/json-schema.test.js +204 -0
  129. package/dist/schema/json-schema.test.js.map +1 -0
  130. package/dist/schema/schema.test.js +237 -0
  131. package/dist/schema/schema.test.js.map +1 -1
  132. package/dist/schema/standard-schema.d.ts +1 -0
  133. package/dist/schema/standard-schema.d.ts.map +1 -1
  134. package/dist/schema/standard-schema.js +18 -13
  135. package/dist/schema/standard-schema.js.map +1 -1
  136. package/dist/schema/standard-schema.test.d.ts +2 -0
  137. package/dist/schema/standard-schema.test.d.ts.map +1 -0
  138. package/dist/schema/standard-schema.test.js +165 -0
  139. package/dist/schema/standard-schema.test.js.map +1 -0
  140. package/dist/schema/validate.test.js +149 -0
  141. package/dist/schema/validate.test.js.map +1 -1
  142. package/dist/schema/zod.d.ts +7 -4
  143. package/dist/schema/zod.d.ts.map +1 -1
  144. package/dist/schema/zod.js +65 -22
  145. package/dist/schema/zod.js.map +1 -1
  146. package/dist/schema/zod.test.js +112 -0
  147. package/dist/schema/zod.test.js.map +1 -1
  148. package/dist/setupTests.js +3 -0
  149. package/dist/setupTests.js.map +1 -1
  150. package/dist/testing/tools.d.ts +4 -1
  151. package/dist/testing/tools.d.ts.map +1 -1
  152. package/dist/testing/tools.js +6 -1
  153. package/dist/testing/tools.js.map +1 -1
  154. package/dist/util/generate-component.d.ts.map +1 -1
  155. package/dist/util/generate-component.js +18 -3
  156. package/dist/util/generate-component.js.map +1 -1
  157. package/dist/util/generate-component.test.d.ts +2 -0
  158. package/dist/util/generate-component.test.d.ts.map +1 -0
  159. package/dist/util/generate-component.test.js +340 -0
  160. package/dist/util/generate-component.test.js.map +1 -0
  161. package/dist/util/is-promise.d.ts +9 -0
  162. package/dist/util/is-promise.d.ts.map +1 -0
  163. package/dist/util/is-promise.js +20 -0
  164. package/dist/util/is-promise.js.map +1 -0
  165. package/dist/util/is-promise.test.d.ts +2 -0
  166. package/dist/util/is-promise.test.d.ts.map +1 -0
  167. package/dist/util/is-promise.test.js +48 -0
  168. package/dist/util/is-promise.test.js.map +1 -0
  169. package/dist/util/message-builder.d.ts +3 -1
  170. package/dist/util/message-builder.d.ts.map +1 -1
  171. package/dist/util/message-builder.js +20 -3
  172. package/dist/util/message-builder.js.map +1 -1
  173. package/dist/util/message-builder.test.js +269 -0
  174. package/dist/util/message-builder.test.js.map +1 -1
  175. package/dist/util/query-utils.test.d.ts +2 -0
  176. package/dist/util/query-utils.test.d.ts.map +1 -0
  177. package/dist/util/query-utils.test.js +382 -0
  178. package/dist/util/query-utils.test.js.map +1 -0
  179. package/dist/util/registry-validators.d.ts.map +1 -1
  180. package/dist/util/registry-validators.js +7 -0
  181. package/dist/util/registry-validators.js.map +1 -1
  182. package/dist/util/registry-validators.test.js +57 -0
  183. package/dist/util/registry-validators.test.js.map +1 -1
  184. package/dist/util/registry.d.ts.map +1 -1
  185. package/dist/util/registry.js +9 -0
  186. package/dist/util/registry.js.map +1 -1
  187. package/dist/util/registry.test.js +323 -1
  188. package/dist/util/registry.test.js.map +1 -1
  189. package/dist/util/resource-content-resolver.d.ts +20 -0
  190. package/dist/util/resource-content-resolver.d.ts.map +1 -0
  191. package/dist/util/resource-content-resolver.js +93 -0
  192. package/dist/util/resource-content-resolver.js.map +1 -0
  193. package/dist/util/resource-content-resolver.test.d.ts +2 -0
  194. package/dist/util/resource-content-resolver.test.d.ts.map +1 -0
  195. package/dist/util/resource-content-resolver.test.js +254 -0
  196. package/dist/util/resource-content-resolver.test.js.map +1 -0
  197. package/dist/util/resource-validators.test.d.ts +2 -0
  198. package/dist/util/resource-validators.test.d.ts.map +1 -0
  199. package/dist/util/resource-validators.test.js +90 -0
  200. package/dist/util/resource-validators.test.js.map +1 -0
  201. package/dist/util/tool-caller.d.ts +2 -2
  202. package/dist/util/tool-caller.d.ts.map +1 -1
  203. package/dist/util/tool-caller.js +8 -8
  204. package/dist/util/tool-caller.js.map +1 -1
  205. package/dist/util/validate-component-name.test.d.ts +2 -0
  206. package/dist/util/validate-component-name.test.d.ts.map +1 -0
  207. package/dist/util/validate-component-name.test.js +35 -0
  208. package/dist/util/validate-component-name.test.js.map +1 -0
  209. package/esm/context-helpers/context-helpers.test.js +16 -4
  210. package/esm/context-helpers/context-helpers.test.js.map +1 -1
  211. package/esm/context-helpers/current-interactables-context-helper.d.ts +2 -2
  212. package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  213. package/esm/context-helpers/current-interactables-context-helper.js +31 -12
  214. package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
  215. package/esm/context-helpers/registry.d.ts +2 -2
  216. package/esm/context-helpers/registry.d.ts.map +1 -1
  217. package/esm/context-helpers/registry.js.map +1 -1
  218. package/esm/context-helpers/types.d.ts +2 -2
  219. package/esm/context-helpers/types.d.ts.map +1 -1
  220. package/esm/context-helpers/types.js.map +1 -1
  221. package/esm/hoc/with-tambo-interactable.d.ts +50 -4
  222. package/esm/hoc/with-tambo-interactable.d.ts.map +1 -1
  223. package/esm/hoc/with-tambo-interactable.js +20 -5
  224. package/esm/hoc/with-tambo-interactable.js.map +1 -1
  225. package/esm/hooks/use-component-state.d.ts +3 -8
  226. package/esm/hooks/use-component-state.d.ts.map +1 -1
  227. package/esm/hooks/use-component-state.js +8 -0
  228. package/esm/hooks/use-component-state.js.map +1 -1
  229. package/esm/hooks/use-component-state.test.js +37 -0
  230. package/esm/hooks/use-component-state.test.js.map +1 -1
  231. package/esm/hooks/use-message-images.test.js +174 -37
  232. package/esm/hooks/use-message-images.test.js.map +1 -1
  233. package/esm/hooks/use-tambo-threads.js +1 -1
  234. package/esm/hooks/use-tambo-threads.js.map +1 -1
  235. package/esm/hooks/use-tambo-voice.d.ts +1 -1
  236. package/esm/hooks/use-tambo-voice.js +1 -1
  237. package/esm/hooks/use-tambo-voice.js.map +1 -1
  238. package/esm/hooks/use-tambo-voice.test.d.ts +2 -0
  239. package/esm/hooks/use-tambo-voice.test.d.ts.map +1 -0
  240. package/esm/hooks/use-tambo-voice.test.js +234 -0
  241. package/esm/hooks/use-tambo-voice.test.js.map +1 -0
  242. package/esm/index.d.ts +2 -2
  243. package/esm/index.d.ts.map +1 -1
  244. package/esm/index.js.map +1 -1
  245. package/esm/mcp/elicitation.d.ts.map +1 -1
  246. package/esm/mcp/elicitation.js +12 -0
  247. package/esm/mcp/elicitation.js.map +1 -1
  248. package/esm/mcp/elicitation.test.js +8 -1
  249. package/esm/mcp/elicitation.test.js.map +1 -1
  250. package/esm/mcp/mcp-client.d.ts +6 -10
  251. package/esm/mcp/mcp-client.d.ts.map +1 -1
  252. package/esm/mcp/mcp-client.js.map +1 -1
  253. package/esm/mcp/mcp-constants.d.ts +19 -0
  254. package/esm/mcp/mcp-constants.d.ts.map +1 -0
  255. package/esm/mcp/mcp-constants.js +18 -0
  256. package/esm/mcp/mcp-constants.js.map +1 -0
  257. package/esm/mcp/mcp-hooks.d.ts +21 -40
  258. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  259. package/esm/mcp/mcp-hooks.js +97 -40
  260. package/esm/mcp/mcp-hooks.js.map +1 -1
  261. package/esm/mcp/mcp-hooks.test.js +431 -5
  262. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  263. package/esm/mcp/tambo-mcp-provider.d.ts +7 -0
  264. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  265. package/esm/mcp/tambo-mcp-provider.js +204 -154
  266. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  267. package/esm/mcp/tambo-mcp-provider.test.js +37 -0
  268. package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
  269. package/esm/model/component-metadata.d.ts +54 -21
  270. package/esm/model/component-metadata.d.ts.map +1 -1
  271. package/esm/model/component-metadata.js.map +1 -1
  272. package/esm/model/tambo-interactable.d.ts +13 -5
  273. package/esm/model/tambo-interactable.d.ts.map +1 -1
  274. package/esm/model/tambo-interactable.js.map +1 -1
  275. package/esm/providers/__tests__/thread-input-resource-resolution.test.d.ts +2 -0
  276. package/esm/providers/__tests__/thread-input-resource-resolution.test.d.ts.map +1 -0
  277. package/esm/providers/__tests__/thread-input-resource-resolution.test.js +587 -0
  278. package/esm/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -0
  279. package/esm/providers/index.d.ts +1 -1
  280. package/esm/providers/index.d.ts.map +1 -1
  281. package/esm/providers/index.js.map +1 -1
  282. package/esm/providers/tambo-client-provider.d.ts +8 -0
  283. package/esm/providers/tambo-client-provider.d.ts.map +1 -1
  284. package/esm/providers/tambo-client-provider.js +11 -12
  285. package/esm/providers/tambo-client-provider.js.map +1 -1
  286. package/esm/providers/tambo-client-provider.test.d.ts +2 -0
  287. package/esm/providers/tambo-client-provider.test.d.ts.map +1 -0
  288. package/esm/providers/tambo-client-provider.test.js +203 -0
  289. package/esm/providers/tambo-client-provider.test.js.map +1 -0
  290. package/esm/providers/tambo-context-attachment-provider.d.ts +34 -92
  291. package/esm/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  292. package/esm/providers/tambo-context-attachment-provider.js +63 -106
  293. package/esm/providers/tambo-context-attachment-provider.js.map +1 -1
  294. package/esm/providers/tambo-context-attachment-provider.test.js +230 -464
  295. package/esm/providers/tambo-context-attachment-provider.test.js.map +1 -1
  296. package/esm/providers/tambo-interactable-provider-partial-updates.test.js +22 -21
  297. package/esm/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  298. package/esm/providers/tambo-interactable-provider.d.ts +5 -2
  299. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  300. package/esm/providers/tambo-interactable-provider.js +126 -17
  301. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  302. package/esm/providers/tambo-interactable-provider.test.js +242 -0
  303. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  304. package/esm/providers/tambo-interactables-additional-context.test.js +2 -5
  305. package/esm/providers/tambo-interactables-additional-context.test.js.map +1 -1
  306. package/esm/providers/tambo-provider.d.ts +2 -3
  307. package/esm/providers/tambo-provider.d.ts.map +1 -1
  308. package/esm/providers/tambo-provider.js +6 -5
  309. package/esm/providers/tambo-provider.js.map +1 -1
  310. package/esm/providers/tambo-registry-provider.test.js +16 -0
  311. package/esm/providers/tambo-registry-provider.test.js.map +1 -1
  312. package/esm/providers/tambo-registry-schema-compat.test.js +31 -0
  313. package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -1
  314. package/esm/providers/tambo-thread-input-provider.d.ts +1 -1
  315. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  316. package/esm/providers/tambo-thread-input-provider.js +26 -4
  317. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  318. package/esm/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  319. package/esm/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  320. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  321. package/esm/providers/tambo-thread-provider.js +53 -42
  322. package/esm/providers/tambo-thread-provider.js.map +1 -1
  323. package/esm/providers/tambo-thread-provider.test.js +368 -262
  324. package/esm/providers/tambo-thread-provider.test.js.map +1 -1
  325. package/esm/schema/index.d.ts +1 -1
  326. package/esm/schema/index.d.ts.map +1 -1
  327. package/esm/schema/index.js +1 -1
  328. package/esm/schema/index.js.map +1 -1
  329. package/esm/schema/json-schema.d.ts +7 -0
  330. package/esm/schema/json-schema.d.ts.map +1 -1
  331. package/esm/schema/json-schema.js +11 -1
  332. package/esm/schema/json-schema.js.map +1 -1
  333. package/esm/schema/json-schema.test.d.ts +2 -0
  334. package/esm/schema/json-schema.test.d.ts.map +1 -0
  335. package/esm/schema/json-schema.test.js +202 -0
  336. package/esm/schema/json-schema.test.js.map +1 -0
  337. package/esm/schema/schema.test.js +238 -1
  338. package/esm/schema/schema.test.js.map +1 -1
  339. package/esm/schema/standard-schema.d.ts +1 -0
  340. package/esm/schema/standard-schema.d.ts.map +1 -1
  341. package/esm/schema/standard-schema.js +18 -13
  342. package/esm/schema/standard-schema.js.map +1 -1
  343. package/esm/schema/standard-schema.test.d.ts +2 -0
  344. package/esm/schema/standard-schema.test.d.ts.map +1 -0
  345. package/esm/schema/standard-schema.test.js +130 -0
  346. package/esm/schema/standard-schema.test.js.map +1 -0
  347. package/esm/schema/validate.test.js +149 -0
  348. package/esm/schema/validate.test.js.map +1 -1
  349. package/esm/schema/zod.d.ts +7 -4
  350. package/esm/schema/zod.d.ts.map +1 -1
  351. package/esm/schema/zod.js +65 -22
  352. package/esm/schema/zod.js.map +1 -1
  353. package/esm/schema/zod.test.js +113 -1
  354. package/esm/schema/zod.test.js.map +1 -1
  355. package/esm/setupTests.js +3 -0
  356. package/esm/setupTests.js.map +1 -1
  357. package/esm/testing/tools.d.ts +4 -1
  358. package/esm/testing/tools.d.ts.map +1 -1
  359. package/esm/testing/tools.js +6 -1
  360. package/esm/testing/tools.js.map +1 -1
  361. package/esm/util/generate-component.d.ts.map +1 -1
  362. package/esm/util/generate-component.js +18 -3
  363. package/esm/util/generate-component.js.map +1 -1
  364. package/esm/util/generate-component.test.d.ts +2 -0
  365. package/esm/util/generate-component.test.d.ts.map +1 -0
  366. package/esm/util/generate-component.test.js +302 -0
  367. package/esm/util/generate-component.test.js.map +1 -0
  368. package/esm/util/is-promise.d.ts +9 -0
  369. package/esm/util/is-promise.d.ts.map +1 -0
  370. package/esm/util/is-promise.js +17 -0
  371. package/esm/util/is-promise.js.map +1 -0
  372. package/esm/util/is-promise.test.d.ts +2 -0
  373. package/esm/util/is-promise.test.d.ts.map +1 -0
  374. package/esm/util/is-promise.test.js +46 -0
  375. package/esm/util/is-promise.test.js.map +1 -0
  376. package/esm/util/message-builder.d.ts +3 -1
  377. package/esm/util/message-builder.d.ts.map +1 -1
  378. package/esm/util/message-builder.js +20 -3
  379. package/esm/util/message-builder.js.map +1 -1
  380. package/esm/util/message-builder.test.js +269 -0
  381. package/esm/util/message-builder.test.js.map +1 -1
  382. package/esm/util/query-utils.test.d.ts +2 -0
  383. package/esm/util/query-utils.test.d.ts.map +1 -0
  384. package/esm/util/query-utils.test.js +380 -0
  385. package/esm/util/query-utils.test.js.map +1 -0
  386. package/esm/util/registry-validators.d.ts.map +1 -1
  387. package/esm/util/registry-validators.js +7 -0
  388. package/esm/util/registry-validators.js.map +1 -1
  389. package/esm/util/registry-validators.test.js +57 -0
  390. package/esm/util/registry-validators.test.js.map +1 -1
  391. package/esm/util/registry.d.ts.map +1 -1
  392. package/esm/util/registry.js +9 -0
  393. package/esm/util/registry.js.map +1 -1
  394. package/esm/util/registry.test.js +324 -2
  395. package/esm/util/registry.test.js.map +1 -1
  396. package/esm/util/resource-content-resolver.d.ts +20 -0
  397. package/esm/util/resource-content-resolver.d.ts.map +1 -0
  398. package/esm/util/resource-content-resolver.js +89 -0
  399. package/esm/util/resource-content-resolver.js.map +1 -0
  400. package/esm/util/resource-content-resolver.test.d.ts +2 -0
  401. package/esm/util/resource-content-resolver.test.d.ts.map +1 -0
  402. package/esm/util/resource-content-resolver.test.js +252 -0
  403. package/esm/util/resource-content-resolver.test.js.map +1 -0
  404. package/esm/util/resource-validators.test.d.ts +2 -0
  405. package/esm/util/resource-validators.test.d.ts.map +1 -0
  406. package/esm/util/resource-validators.test.js +88 -0
  407. package/esm/util/resource-validators.test.js.map +1 -0
  408. package/esm/util/tool-caller.d.ts +2 -2
  409. package/esm/util/tool-caller.d.ts.map +1 -1
  410. package/esm/util/tool-caller.js +8 -8
  411. package/esm/util/tool-caller.js.map +1 -1
  412. package/esm/util/validate-component-name.test.d.ts +2 -0
  413. package/esm/util/validate-component-name.test.d.ts.map +1 -0
  414. package/esm/util/validate-component-name.test.js +33 -0
  415. package/esm/util/validate-component-name.test.js.map +1 -0
  416. package/package.json +15 -23
  417. package/dist/schema/alias.d.ts +0 -3
  418. package/dist/schema/alias.d.ts.map +0 -1
  419. package/dist/schema/alias.js +0 -6
  420. package/dist/schema/alias.js.map +0 -1
  421. package/esm/schema/alias.d.ts +0 -3
  422. package/esm/schema/alias.d.ts.map +0 -1
  423. package/esm/schema/alias.js +0 -13
  424. package/esm/schema/alias.js.map +0 -1
@@ -110,8 +110,18 @@ describe("TamboThreadProvider", () => {
110
110
  ],
111
111
  },
112
112
  ];
113
- // Use helpers that explicitly return null so they don't appear in additionalContext
114
- const Wrapper = ({ children }) => {
113
+ /**
114
+ * Creates a test wrapper component with configurable options.
115
+ * Reduces duplication across tests by centralizing provider setup.
116
+ * @param options - Configuration options for the wrapper
117
+ * @param options.components - The Tambo components to register
118
+ * @param options.streaming - Whether to enable streaming responses
119
+ * @param options.onCallUnregisteredTool - Handler for unregistered tool calls
120
+ * @param options.autoGenerateThreadName - Whether to auto-generate thread names
121
+ * @param options.autoGenerateNameThreshold - Token threshold for auto-generating names
122
+ * @returns A React component that wraps children with the necessary providers
123
+ */
124
+ const createWrapper = ({ components = mockRegistry, streaming = false, onCallUnregisteredTool, autoGenerateThreadName, autoGenerateNameThreshold, } = {}) => function TestWrapper({ children }) {
115
125
  const client = useTamboClient();
116
126
  const queryClient = useTamboQueryClient();
117
127
  return (React.createElement(TamboClientContext.Provider, { value: {
@@ -119,14 +129,16 @@ describe("TamboThreadProvider", () => {
119
129
  queryClient,
120
130
  isUpdatingToken: false,
121
131
  } },
122
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
132
+ React.createElement(TamboRegistryProvider, { components: components, onCallUnregisteredTool: onCallUnregisteredTool },
123
133
  React.createElement(TamboContextHelpersProvider, { contextHelpers: {
124
134
  currentTimeContextHelper: () => null,
125
135
  currentPageContextHelper: () => null,
126
136
  } },
127
137
  React.createElement(TamboMcpTokenProvider, null,
128
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
138
+ React.createElement(TamboThreadProvider, { streaming: streaming, autoGenerateThreadName: autoGenerateThreadName, autoGenerateNameThreshold: autoGenerateNameThreshold }, children))))));
129
139
  };
140
+ // Default wrapper for most tests
141
+ const Wrapper = createWrapper();
130
142
  beforeEach(() => {
131
143
  jest.clearAllMocks();
132
144
  // Setup mock query client
@@ -344,22 +356,6 @@ describe("TamboThreadProvider", () => {
344
356
  const mockOnCallUnregisteredTool = jest
345
357
  .fn()
346
358
  .mockResolvedValue("unregistered-tool-result");
347
- const WrapperWithUnregisteredTool = ({ children, }) => {
348
- const client = useTamboClient();
349
- const queryClient = useTamboQueryClient();
350
- return (React.createElement(TamboClientContext.Provider, { value: {
351
- client,
352
- queryClient,
353
- isUpdatingToken: false,
354
- } },
355
- React.createElement(TamboRegistryProvider, { components: mockRegistry, onCallUnregisteredTool: mockOnCallUnregisteredTool },
356
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
357
- currentTimeContextHelper: () => null,
358
- currentPageContextHelper: () => null,
359
- } },
360
- React.createElement(TamboMcpTokenProvider, null,
361
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
362
- };
363
359
  const mockUnregisteredToolCallResponse = {
364
360
  responseMessageDto: {
365
361
  id: "unregistered-tool-call-1",
@@ -394,7 +390,9 @@ describe("TamboThreadProvider", () => {
394
390
  mcpAccessToken: "test-mcp-access-token",
395
391
  });
396
392
  const { result } = renderHook(() => useTamboThread(), {
397
- wrapper: WrapperWithUnregisteredTool,
393
+ wrapper: createWrapper({
394
+ onCallUnregisteredTool: mockOnCallUnregisteredTool,
395
+ }),
398
396
  });
399
397
  await act(async () => {
400
398
  await result.current.sendThreadMessage("Use unregistered tool", {
@@ -451,23 +449,6 @@ describe("TamboThreadProvider", () => {
451
449
  });
452
450
  describe("streaming behavior", () => {
453
451
  it("should call advanceStream when streamResponse=true", async () => {
454
- // Use wrapper with streaming=true to show that explicit streamResponse=true works
455
- const WrapperWithStreaming = ({ children, }) => {
456
- const client = useTamboClient();
457
- const queryClient = useTamboQueryClient();
458
- return (React.createElement(TamboClientContext.Provider, { value: {
459
- client,
460
- queryClient,
461
- isUpdatingToken: false,
462
- } },
463
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
464
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
465
- currentTimeContextHelper: () => null,
466
- currentPageContextHelper: () => null,
467
- } },
468
- React.createElement(TamboMcpTokenProvider, null,
469
- React.createElement(TamboThreadProvider, { streaming: true }, children))))));
470
- };
471
452
  const mockStreamResponse = {
472
453
  responseMessageDto: {
473
454
  id: "stream-response",
@@ -488,7 +469,7 @@ describe("TamboThreadProvider", () => {
488
469
  };
489
470
  jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
490
471
  const { result } = renderHook(() => useTamboThread(), {
491
- wrapper: WrapperWithStreaming,
472
+ wrapper: createWrapper({ streaming: true }),
492
473
  });
493
474
  await act(async () => {
494
475
  await result.current.sendThreadMessage("Hello streaming", {
@@ -523,24 +504,8 @@ describe("TamboThreadProvider", () => {
523
504
  });
524
505
  it("should call advanceById when streamResponse=false for existing thread", async () => {
525
506
  // Use wrapper with streaming=true to show that explicit streamResponse=false overrides provider setting
526
- const WrapperWithStreaming = ({ children, }) => {
527
- const client = useTamboClient();
528
- const queryClient = useTamboQueryClient();
529
- return (React.createElement(TamboClientContext.Provider, { value: {
530
- client,
531
- queryClient,
532
- isUpdatingToken: false,
533
- } },
534
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
535
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
536
- currentTimeContextHelper: () => null,
537
- currentPageContextHelper: () => null,
538
- } },
539
- React.createElement(TamboMcpTokenProvider, null,
540
- React.createElement(TamboThreadProvider, { streaming: true }, children))))));
541
- };
542
507
  const { result } = renderHook(() => useTamboThread(), {
543
- wrapper: WrapperWithStreaming,
508
+ wrapper: createWrapper({ streaming: true }),
544
509
  });
545
510
  await act(async () => {
546
511
  await result.current.sendThreadMessage("Hello non-streaming", {
@@ -575,24 +540,8 @@ describe("TamboThreadProvider", () => {
575
540
  });
576
541
  it("should call advanceById when streamResponse is undefined and provider streaming=false", async () => {
577
542
  // Use wrapper with streaming=false to test that undefined streamResponse respects provider setting
578
- const WrapperWithoutStreaming = ({ children, }) => {
579
- const client = useTamboClient();
580
- const queryClient = useTamboQueryClient();
581
- return (React.createElement(TamboClientContext.Provider, { value: {
582
- client,
583
- queryClient,
584
- isUpdatingToken: false,
585
- } },
586
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
587
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
588
- currentTimeContextHelper: () => null,
589
- currentPageContextHelper: () => null,
590
- } },
591
- React.createElement(TamboMcpTokenProvider, null,
592
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
593
- };
594
543
  const { result } = renderHook(() => useTamboThread(), {
595
- wrapper: WrapperWithoutStreaming,
544
+ wrapper: createWrapper({ streaming: false }),
596
545
  });
597
546
  await act(async () => {
598
547
  await result.current.sendThreadMessage("Hello default", {
@@ -626,23 +575,6 @@ describe("TamboThreadProvider", () => {
626
575
  expect(advanceStream).not.toHaveBeenCalled();
627
576
  });
628
577
  it("should call advanceStream when streamResponse is undefined and provider streaming=true (default)", async () => {
629
- // Use wrapper with streaming=true (default) to test that undefined streamResponse respects provider setting
630
- const WrapperWithDefaultStreaming = ({ children, }) => {
631
- const client = useTamboClient();
632
- const queryClient = useTamboQueryClient();
633
- return (React.createElement(TamboClientContext.Provider, { value: {
634
- client,
635
- queryClient,
636
- isUpdatingToken: false,
637
- } },
638
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
639
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
640
- currentTimeContextHelper: () => null,
641
- currentPageContextHelper: () => null,
642
- } },
643
- React.createElement(TamboMcpTokenProvider, null,
644
- React.createElement(TamboThreadProvider, null, children))))));
645
- };
646
578
  const mockStreamResponse = {
647
579
  responseMessageDto: {
648
580
  id: "stream-response",
@@ -663,7 +595,7 @@ describe("TamboThreadProvider", () => {
663
595
  };
664
596
  jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
665
597
  const { result } = renderHook(() => useTamboThread(), {
666
- wrapper: WrapperWithDefaultStreaming,
598
+ wrapper: createWrapper({ streaming: true }),
667
599
  });
668
600
  await act(async () => {
669
601
  await result.current.sendThreadMessage("Hello default streaming", {
@@ -698,24 +630,8 @@ describe("TamboThreadProvider", () => {
698
630
  });
699
631
  it("should call advance when streamResponse=false for placeholder thread", async () => {
700
632
  // Use wrapper with streaming=true to show that explicit streamResponse=false overrides provider setting
701
- const WrapperWithStreaming = ({ children, }) => {
702
- const client = useTamboClient();
703
- const queryClient = useTamboQueryClient();
704
- return (React.createElement(TamboClientContext.Provider, { value: {
705
- client,
706
- queryClient,
707
- isUpdatingToken: false,
708
- } },
709
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
710
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
711
- currentTimeContextHelper: () => null,
712
- currentPageContextHelper: () => null,
713
- } },
714
- React.createElement(TamboMcpTokenProvider, null,
715
- React.createElement(TamboThreadProvider, { streaming: true }, children))))));
716
- };
717
633
  const { result } = renderHook(() => useTamboThread(), {
718
- wrapper: WrapperWithStreaming,
634
+ wrapper: createWrapper({ streaming: true }),
719
635
  });
720
636
  // Start with placeholder thread (which is the default state)
721
637
  expect(result.current.thread.id).toBe("placeholder");
@@ -751,23 +667,6 @@ describe("TamboThreadProvider", () => {
751
667
  expect(advanceStream).not.toHaveBeenCalled();
752
668
  });
753
669
  it("should call advanceStream when streamResponse=true for placeholder thread", async () => {
754
- // Use wrapper with streaming=false to show that explicit streamResponse=true overrides provider setting
755
- const WrapperWithoutStreaming = ({ children, }) => {
756
- const client = useTamboClient();
757
- const queryClient = useTamboQueryClient();
758
- return (React.createElement(TamboClientContext.Provider, { value: {
759
- client,
760
- queryClient,
761
- isUpdatingToken: false,
762
- } },
763
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
764
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
765
- currentTimeContextHelper: () => null,
766
- currentPageContextHelper: () => null,
767
- } },
768
- React.createElement(TamboMcpTokenProvider, null,
769
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
770
- };
771
670
  const mockStreamResponse = {
772
671
  responseMessageDto: {
773
672
  id: "stream-response",
@@ -788,7 +687,7 @@ describe("TamboThreadProvider", () => {
788
687
  };
789
688
  jest.mocked(advanceStream).mockResolvedValue(mockAsyncIterator);
790
689
  const { result } = renderHook(() => useTamboThread(), {
791
- wrapper: WrapperWithoutStreaming,
690
+ wrapper: createWrapper({ streaming: false }),
792
691
  });
793
692
  // Start with placeholder thread (which is the default state)
794
693
  expect(result.current.thread.id).toBe("placeholder");
@@ -973,22 +872,6 @@ describe("TamboThreadProvider", () => {
973
872
  ],
974
873
  },
975
874
  ];
976
- const WrapperWithCustomTool = ({ children, }) => {
977
- const client = useTamboClient();
978
- const queryClient = useTamboQueryClient();
979
- return (React.createElement(TamboClientContext.Provider, { value: {
980
- client,
981
- queryClient,
982
- isUpdatingToken: false,
983
- } },
984
- React.createElement(TamboRegistryProvider, { components: customToolRegistry },
985
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
986
- currentTimeContextHelper: () => null,
987
- currentPageContextHelper: () => null,
988
- } },
989
- React.createElement(TamboMcpTokenProvider, null,
990
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
991
- };
992
875
  const mockToolCallResponse = {
993
876
  responseMessageDto: {
994
877
  id: "tool-call-1",
@@ -1021,7 +904,7 @@ describe("TamboThreadProvider", () => {
1021
904
  mcpAccessToken: "test-mcp-access-token",
1022
905
  });
1023
906
  const { result } = renderHook(() => useTamboThread(), {
1024
- wrapper: WrapperWithCustomTool,
907
+ wrapper: createWrapper({ components: customToolRegistry }),
1025
908
  });
1026
909
  await act(async () => {
1027
910
  await result.current.sendThreadMessage("Use custom tool", {
@@ -1074,22 +957,6 @@ describe("TamboThreadProvider", () => {
1074
957
  ],
1075
958
  },
1076
959
  ];
1077
- const WrapperWithAsyncTool = ({ children, }) => {
1078
- const client = useTamboClient();
1079
- const queryClient = useTamboQueryClient();
1080
- return (React.createElement(TamboClientContext.Provider, { value: {
1081
- client,
1082
- queryClient,
1083
- isUpdatingToken: false,
1084
- } },
1085
- React.createElement(TamboRegistryProvider, { components: customToolRegistry },
1086
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1087
- currentTimeContextHelper: () => null,
1088
- currentPageContextHelper: () => null,
1089
- } },
1090
- React.createElement(TamboMcpTokenProvider, null,
1091
- React.createElement(TamboThreadProvider, { streaming: true }, children))))));
1092
- };
1093
960
  const mockToolCallChunk = {
1094
961
  responseMessageDto: {
1095
962
  id: "tool-call-chunk",
@@ -1135,7 +1002,10 @@ describe("TamboThreadProvider", () => {
1135
1002
  },
1136
1003
  });
1137
1004
  const { result } = renderHook(() => useTamboThread(), {
1138
- wrapper: WrapperWithAsyncTool,
1005
+ wrapper: createWrapper({
1006
+ components: customToolRegistry,
1007
+ streaming: true,
1008
+ }),
1139
1009
  });
1140
1010
  await act(async () => {
1141
1011
  await result.current.sendThreadMessage("Use async tool", {
@@ -1183,22 +1053,6 @@ describe("TamboThreadProvider", () => {
1183
1053
  ],
1184
1054
  },
1185
1055
  ];
1186
- const WrapperWithoutTransform = ({ children, }) => {
1187
- const client = useTamboClient();
1188
- const queryClient = useTamboQueryClient();
1189
- return (React.createElement(TamboClientContext.Provider, { value: {
1190
- client,
1191
- queryClient,
1192
- isUpdatingToken: false,
1193
- } },
1194
- React.createElement(TamboRegistryProvider, { components: toolWithoutTransform },
1195
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1196
- currentTimeContextHelper: () => null,
1197
- currentPageContextHelper: () => null,
1198
- } },
1199
- React.createElement(TamboMcpTokenProvider, null,
1200
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
1201
- };
1202
1056
  const mockToolCallResponse = {
1203
1057
  responseMessageDto: {
1204
1058
  id: "tool-call-1",
@@ -1231,7 +1085,7 @@ describe("TamboThreadProvider", () => {
1231
1085
  mcpAccessToken: "test-mcp-access-token",
1232
1086
  });
1233
1087
  const { result } = renderHook(() => useTamboThread(), {
1234
- wrapper: WrapperWithoutTransform,
1088
+ wrapper: createWrapper({ components: toolWithoutTransform }),
1235
1089
  });
1236
1090
  await act(async () => {
1237
1091
  await result.current.sendThreadMessage("Use tool without transform", {
@@ -1281,22 +1135,6 @@ describe("TamboThreadProvider", () => {
1281
1135
  ],
1282
1136
  },
1283
1137
  ];
1284
- const WrapperWithErrorTool = ({ children, }) => {
1285
- const client = useTamboClient();
1286
- const queryClient = useTamboQueryClient();
1287
- return (React.createElement(TamboClientContext.Provider, { value: {
1288
- client,
1289
- queryClient,
1290
- isUpdatingToken: false,
1291
- } },
1292
- React.createElement(TamboRegistryProvider, { components: toolWithTransform },
1293
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1294
- currentTimeContextHelper: () => null,
1295
- currentPageContextHelper: () => null,
1296
- } },
1297
- React.createElement(TamboMcpTokenProvider, null,
1298
- React.createElement(TamboThreadProvider, { streaming: false }, children))))));
1299
- };
1300
1138
  const mockToolCallResponse = {
1301
1139
  responseMessageDto: {
1302
1140
  id: "tool-call-1",
@@ -1329,7 +1167,7 @@ describe("TamboThreadProvider", () => {
1329
1167
  mcpAccessToken: "test-mcp-access-token",
1330
1168
  });
1331
1169
  const { result } = renderHook(() => useTamboThread(), {
1332
- wrapper: WrapperWithErrorTool,
1170
+ wrapper: createWrapper({ components: toolWithTransform }),
1333
1171
  });
1334
1172
  await act(async () => {
1335
1173
  await result.current.sendThreadMessage("Use error tool", {
@@ -1355,26 +1193,339 @@ describe("TamboThreadProvider", () => {
1355
1193
  }));
1356
1194
  });
1357
1195
  });
1196
+ describe("tamboStreamableHint streaming behavior", () => {
1197
+ it("should call streamable tool during streaming when tamboStreamableHint is true", async () => {
1198
+ const streamableToolFn = jest
1199
+ .fn()
1200
+ .mockResolvedValue({ data: "streamed" });
1201
+ const customToolRegistry = [
1202
+ {
1203
+ name: "TestComponent",
1204
+ component: () => React.createElement("div", null, "Test"),
1205
+ description: "Test",
1206
+ propsSchema: z.object({ test: z.string() }),
1207
+ associatedTools: [
1208
+ {
1209
+ name: "streamable-tool",
1210
+ tool: streamableToolFn,
1211
+ description: "Tool safe for streaming",
1212
+ inputSchema: z.object({ input: z.string() }),
1213
+ outputSchema: z.object({ data: z.string() }),
1214
+ annotations: { tamboStreamableHint: true },
1215
+ },
1216
+ ],
1217
+ },
1218
+ ];
1219
+ // First chunk initializes finalMessage
1220
+ const mockInitialChunk = {
1221
+ responseMessageDto: {
1222
+ id: "initial-chunk",
1223
+ content: [{ type: "text", text: "Starting..." }],
1224
+ role: "assistant",
1225
+ threadId: "test-thread-1",
1226
+ componentState: {},
1227
+ createdAt: new Date().toISOString(),
1228
+ },
1229
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1230
+ mcpAccessToken: "test-mcp-access-token",
1231
+ };
1232
+ // Second chunk has the tool call - this triggers streaming tool handling
1233
+ const mockToolCallChunk = {
1234
+ responseMessageDto: {
1235
+ id: "initial-chunk", // Same ID as initial - it's an update
1236
+ content: [{ type: "text", text: "Streaming..." }],
1237
+ role: "assistant",
1238
+ threadId: "test-thread-1",
1239
+ component: {
1240
+ componentName: "",
1241
+ componentState: {},
1242
+ message: "",
1243
+ props: {},
1244
+ toolCallRequest: {
1245
+ toolName: "streamable-tool",
1246
+ parameters: [
1247
+ { parameterName: "input", parameterValue: "stream-test" },
1248
+ ],
1249
+ },
1250
+ },
1251
+ componentState: {},
1252
+ createdAt: new Date().toISOString(),
1253
+ },
1254
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1255
+ mcpAccessToken: "test-mcp-access-token",
1256
+ };
1257
+ const mockFinalChunk = {
1258
+ responseMessageDto: {
1259
+ id: "initial-chunk",
1260
+ content: [{ type: "text", text: "Complete" }],
1261
+ role: "assistant",
1262
+ threadId: "test-thread-1",
1263
+ componentState: {},
1264
+ createdAt: new Date().toISOString(),
1265
+ },
1266
+ generationStage: GenerationStage.COMPLETE,
1267
+ mcpAccessToken: "test-mcp-access-token",
1268
+ };
1269
+ const mockAsyncIterator = {
1270
+ [Symbol.asyncIterator]: async function* () {
1271
+ yield mockInitialChunk;
1272
+ yield mockToolCallChunk;
1273
+ yield mockFinalChunk;
1274
+ },
1275
+ };
1276
+ jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
1277
+ const { result } = renderHook(() => useTamboThread(), {
1278
+ wrapper: createWrapper({
1279
+ components: customToolRegistry,
1280
+ streaming: true,
1281
+ }),
1282
+ });
1283
+ await act(async () => {
1284
+ await result.current.sendThreadMessage("Test streamable tool", {
1285
+ threadId: "test-thread-1",
1286
+ streamResponse: true,
1287
+ });
1288
+ });
1289
+ // Streamable tool should be called during streaming
1290
+ expect(streamableToolFn).toHaveBeenCalledWith({ input: "stream-test" });
1291
+ });
1292
+ it("should NOT call non-streamable tool during streaming", async () => {
1293
+ const nonStreamableToolFn = jest
1294
+ .fn()
1295
+ .mockResolvedValue({ data: "result" });
1296
+ const customToolRegistry = [
1297
+ {
1298
+ name: "TestComponent",
1299
+ component: () => React.createElement("div", null, "Test"),
1300
+ description: "Test",
1301
+ propsSchema: z.object({ test: z.string() }),
1302
+ associatedTools: [
1303
+ {
1304
+ name: "non-streamable-tool",
1305
+ tool: nonStreamableToolFn,
1306
+ description: "Tool not safe for streaming",
1307
+ inputSchema: z.object({ input: z.string() }),
1308
+ outputSchema: z.object({ data: z.string() }),
1309
+ // No tamboStreamableHint - defaults to false
1310
+ },
1311
+ ],
1312
+ },
1313
+ ];
1314
+ // First chunk initializes finalMessage
1315
+ const mockInitialChunk = {
1316
+ responseMessageDto: {
1317
+ id: "streaming-chunk",
1318
+ content: [{ type: "text", text: "Starting..." }],
1319
+ role: "assistant",
1320
+ threadId: "test-thread-1",
1321
+ componentState: {},
1322
+ createdAt: new Date().toISOString(),
1323
+ },
1324
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1325
+ mcpAccessToken: "test-mcp-access-token",
1326
+ };
1327
+ // Second chunk has the tool call - but tool is NOT streamable
1328
+ const mockToolCallChunk = {
1329
+ responseMessageDto: {
1330
+ id: "streaming-chunk",
1331
+ content: [{ type: "text", text: "Streaming..." }],
1332
+ role: "assistant",
1333
+ threadId: "test-thread-1",
1334
+ component: {
1335
+ componentName: "",
1336
+ componentState: {},
1337
+ message: "",
1338
+ props: {},
1339
+ toolCallRequest: {
1340
+ toolName: "non-streamable-tool",
1341
+ parameters: [{ parameterName: "input", parameterValue: "test" }],
1342
+ },
1343
+ },
1344
+ componentState: {},
1345
+ createdAt: new Date().toISOString(),
1346
+ },
1347
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1348
+ mcpAccessToken: "test-mcp-access-token",
1349
+ };
1350
+ const mockFinalChunk = {
1351
+ responseMessageDto: {
1352
+ id: "streaming-chunk",
1353
+ content: [{ type: "text", text: "Complete" }],
1354
+ role: "assistant",
1355
+ threadId: "test-thread-1",
1356
+ componentState: {},
1357
+ createdAt: new Date().toISOString(),
1358
+ },
1359
+ generationStage: GenerationStage.COMPLETE,
1360
+ mcpAccessToken: "test-mcp-access-token",
1361
+ };
1362
+ const mockAsyncIterator = {
1363
+ [Symbol.asyncIterator]: async function* () {
1364
+ yield mockInitialChunk;
1365
+ yield mockToolCallChunk;
1366
+ yield mockFinalChunk;
1367
+ },
1368
+ };
1369
+ jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
1370
+ const { result } = renderHook(() => useTamboThread(), {
1371
+ wrapper: createWrapper({
1372
+ components: customToolRegistry,
1373
+ streaming: true,
1374
+ }),
1375
+ });
1376
+ await act(async () => {
1377
+ await result.current.sendThreadMessage("Test non-streamable tool", {
1378
+ threadId: "test-thread-1",
1379
+ streamResponse: true,
1380
+ });
1381
+ });
1382
+ // Non-streamable tool should NOT be called during the streaming chunk phase
1383
+ // (it would only be called when generationStage is COMPLETE with a toolCallRequest)
1384
+ expect(nonStreamableToolFn).not.toHaveBeenCalled();
1385
+ });
1386
+ it("should only call streamable tools during streaming when mixed", async () => {
1387
+ const streamableToolFn = jest
1388
+ .fn()
1389
+ .mockResolvedValue({ data: "streamed" });
1390
+ const nonStreamableToolFn = jest
1391
+ .fn()
1392
+ .mockResolvedValue({ data: "not-streamed" });
1393
+ const customToolRegistry = [
1394
+ {
1395
+ name: "TestComponent",
1396
+ component: () => React.createElement("div", null, "Test"),
1397
+ description: "Test",
1398
+ propsSchema: z.object({ test: z.string() }),
1399
+ associatedTools: [
1400
+ {
1401
+ name: "streamable-tool",
1402
+ tool: streamableToolFn,
1403
+ description: "Tool safe for streaming",
1404
+ inputSchema: z.object({ input: z.string() }),
1405
+ outputSchema: z.object({ data: z.string() }),
1406
+ annotations: { tamboStreamableHint: true },
1407
+ },
1408
+ {
1409
+ name: "non-streamable-tool",
1410
+ tool: nonStreamableToolFn,
1411
+ description: "Tool not safe for streaming",
1412
+ inputSchema: z.object({ input: z.string() }),
1413
+ outputSchema: z.object({ data: z.string() }),
1414
+ annotations: { tamboStreamableHint: false },
1415
+ },
1416
+ ],
1417
+ },
1418
+ ];
1419
+ // First chunk initializes finalMessage
1420
+ const mockInitialChunk = {
1421
+ responseMessageDto: {
1422
+ id: "streaming-chunk",
1423
+ content: [{ type: "text", text: "Starting..." }],
1424
+ role: "assistant",
1425
+ threadId: "test-thread-1",
1426
+ componentState: {},
1427
+ createdAt: new Date().toISOString(),
1428
+ },
1429
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1430
+ mcpAccessToken: "test-mcp-access-token",
1431
+ };
1432
+ // Second chunk calls the streamable tool
1433
+ const mockStreamableToolChunk = {
1434
+ responseMessageDto: {
1435
+ id: "streaming-chunk",
1436
+ content: [{ type: "text", text: "Calling streamable..." }],
1437
+ role: "assistant",
1438
+ threadId: "test-thread-1",
1439
+ component: {
1440
+ componentName: "",
1441
+ componentState: {},
1442
+ message: "",
1443
+ props: {},
1444
+ toolCallRequest: {
1445
+ toolName: "streamable-tool",
1446
+ parameters: [
1447
+ { parameterName: "input", parameterValue: "streamed-input" },
1448
+ ],
1449
+ },
1450
+ },
1451
+ componentState: {},
1452
+ createdAt: new Date().toISOString(),
1453
+ },
1454
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1455
+ mcpAccessToken: "test-mcp-access-token",
1456
+ };
1457
+ // Third chunk calls the non-streamable tool
1458
+ const mockNonStreamableToolChunk = {
1459
+ responseMessageDto: {
1460
+ id: "streaming-chunk",
1461
+ content: [{ type: "text", text: "Calling non-streamable..." }],
1462
+ role: "assistant",
1463
+ threadId: "test-thread-1",
1464
+ component: {
1465
+ componentName: "",
1466
+ componentState: {},
1467
+ message: "",
1468
+ props: {},
1469
+ toolCallRequest: {
1470
+ toolName: "non-streamable-tool",
1471
+ parameters: [
1472
+ {
1473
+ parameterName: "input",
1474
+ parameterValue: "non-streamed-input",
1475
+ },
1476
+ ],
1477
+ },
1478
+ },
1479
+ componentState: {},
1480
+ createdAt: new Date().toISOString(),
1481
+ },
1482
+ generationStage: GenerationStage.STREAMING_RESPONSE,
1483
+ mcpAccessToken: "test-mcp-access-token",
1484
+ };
1485
+ const mockFinalChunk = {
1486
+ responseMessageDto: {
1487
+ id: "streaming-chunk",
1488
+ content: [{ type: "text", text: "Complete" }],
1489
+ role: "assistant",
1490
+ threadId: "test-thread-1",
1491
+ componentState: {},
1492
+ createdAt: new Date().toISOString(),
1493
+ },
1494
+ generationStage: GenerationStage.COMPLETE,
1495
+ mcpAccessToken: "test-mcp-access-token",
1496
+ };
1497
+ const mockAsyncIterator = {
1498
+ [Symbol.asyncIterator]: async function* () {
1499
+ yield mockInitialChunk;
1500
+ yield mockStreamableToolChunk;
1501
+ yield mockNonStreamableToolChunk;
1502
+ yield mockFinalChunk;
1503
+ },
1504
+ };
1505
+ jest.mocked(advanceStream).mockResolvedValueOnce(mockAsyncIterator);
1506
+ const { result } = renderHook(() => useTamboThread(), {
1507
+ wrapper: createWrapper({
1508
+ components: customToolRegistry,
1509
+ streaming: true,
1510
+ }),
1511
+ });
1512
+ await act(async () => {
1513
+ await result.current.sendThreadMessage("Test mixed tools", {
1514
+ threadId: "test-thread-1",
1515
+ streamResponse: true,
1516
+ });
1517
+ });
1518
+ // Only the streamable tool should be called during streaming
1519
+ expect(streamableToolFn).toHaveBeenCalledWith({
1520
+ input: "streamed-input",
1521
+ });
1522
+ expect(nonStreamableToolFn).not.toHaveBeenCalled();
1523
+ });
1524
+ });
1358
1525
  describe("auto-generate thread name", () => {
1359
1526
  it("should auto-generate thread name after reaching threshold", async () => {
1360
- const WrapperWithAutoGenerate = ({ children, }) => {
1361
- const client = useTamboClient();
1362
- const queryClient = useTamboQueryClient();
1363
- return (React.createElement(TamboClientContext.Provider, { value: {
1364
- client,
1365
- queryClient,
1366
- isUpdatingToken: false,
1367
- } },
1368
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
1369
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1370
- currentTimeContextHelper: () => null,
1371
- currentPageContextHelper: () => null,
1372
- } },
1373
- React.createElement(TamboMcpTokenProvider, null,
1374
- React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
1375
- };
1376
1527
  const { result } = renderHook(() => useTamboThread(), {
1377
- wrapper: WrapperWithAutoGenerate,
1528
+ wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
1378
1529
  });
1379
1530
  const existingThread = createMockThread({
1380
1531
  id: "test-thread-1",
@@ -1411,24 +1562,11 @@ describe("TamboThreadProvider", () => {
1411
1562
  expect(mockQueryClient.setQueryData).toHaveBeenCalledWith(["threads", "test-project-id", undefined], expect.any(Function));
1412
1563
  });
1413
1564
  it("should NOT auto-generate when autoGenerateThreadName is false", async () => {
1414
- const WrapperWithDisabled = ({ children, }) => {
1415
- const client = useTamboClient();
1416
- const queryClient = useTamboQueryClient();
1417
- return (React.createElement(TamboClientContext.Provider, { value: {
1418
- client,
1419
- queryClient,
1420
- isUpdatingToken: false,
1421
- } },
1422
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
1423
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1424
- currentTimeContextHelper: () => null,
1425
- currentPageContextHelper: () => null,
1426
- } },
1427
- React.createElement(TamboMcpTokenProvider, null,
1428
- React.createElement(TamboThreadProvider, { streaming: false, autoGenerateThreadName: false, autoGenerateNameThreshold: 2 }, children))))));
1429
- };
1430
1565
  const { result } = renderHook(() => useTamboThread(), {
1431
- wrapper: WrapperWithDisabled,
1566
+ wrapper: createWrapper({
1567
+ autoGenerateThreadName: false,
1568
+ autoGenerateNameThreshold: 2,
1569
+ }),
1432
1570
  });
1433
1571
  const existingThread = createMockThread({
1434
1572
  id: "test-thread-1",
@@ -1461,24 +1599,8 @@ describe("TamboThreadProvider", () => {
1461
1599
  expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
1462
1600
  });
1463
1601
  it("should NOT auto-generate when thread already has a name", async () => {
1464
- const WrapperWithAutoGenerate = ({ children, }) => {
1465
- const client = useTamboClient();
1466
- const queryClient = useTamboQueryClient();
1467
- return (React.createElement(TamboClientContext.Provider, { value: {
1468
- client,
1469
- queryClient,
1470
- isUpdatingToken: false,
1471
- } },
1472
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
1473
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1474
- currentTimeContextHelper: () => null,
1475
- currentPageContextHelper: () => null,
1476
- } },
1477
- React.createElement(TamboMcpTokenProvider, null,
1478
- React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
1479
- };
1480
1602
  const { result } = renderHook(() => useTamboThread(), {
1481
- wrapper: WrapperWithAutoGenerate,
1603
+ wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
1482
1604
  });
1483
1605
  const threadWithName = createMockThread({
1484
1606
  id: "test-thread-1",
@@ -1516,24 +1638,8 @@ describe("TamboThreadProvider", () => {
1516
1638
  expect(mockThreadsApi.generateName).not.toHaveBeenCalled();
1517
1639
  });
1518
1640
  it("should NOT auto-generate for placeholder thread", async () => {
1519
- const WrapperWithAutoGenerate = ({ children, }) => {
1520
- const client = useTamboClient();
1521
- const queryClient = useTamboQueryClient();
1522
- return (React.createElement(TamboClientContext.Provider, { value: {
1523
- client,
1524
- queryClient,
1525
- isUpdatingToken: false,
1526
- } },
1527
- React.createElement(TamboRegistryProvider, { components: mockRegistry },
1528
- React.createElement(TamboContextHelpersProvider, { contextHelpers: {
1529
- currentTimeContextHelper: () => null,
1530
- currentPageContextHelper: () => null,
1531
- } },
1532
- React.createElement(TamboMcpTokenProvider, null,
1533
- React.createElement(TamboThreadProvider, { streaming: false, autoGenerateNameThreshold: 2 }, children))))));
1534
- };
1535
1641
  const { result } = renderHook(() => useTamboThread(), {
1536
- wrapper: WrapperWithAutoGenerate,
1642
+ wrapper: createWrapper({ autoGenerateNameThreshold: 2 }),
1537
1643
  });
1538
1644
  // Stay on placeholder thread
1539
1645
  expect(result.current.thread.id).toBe("placeholder");