@tambo-ai/react 0.68.0 → 0.69.1

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 (326) hide show
  1. package/README.md +1 -1
  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 -15
  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/hooks/use-message-images.test.js +174 -37
  15. package/dist/hooks/use-message-images.test.js.map +1 -1
  16. package/dist/hooks/use-tambo-voice.d.ts +1 -1
  17. package/dist/hooks/use-tambo-voice.js +1 -1
  18. package/dist/hooks/use-tambo-voice.js.map +1 -1
  19. package/dist/hooks/use-tambo-voice.test.d.ts +2 -0
  20. package/dist/hooks/use-tambo-voice.test.d.ts.map +1 -0
  21. package/dist/hooks/use-tambo-voice.test.js +239 -0
  22. package/dist/hooks/use-tambo-voice.test.js.map +1 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp/elicitation.d.ts.map +1 -1
  27. package/dist/mcp/elicitation.js +12 -0
  28. package/dist/mcp/elicitation.js.map +1 -1
  29. package/dist/mcp/elicitation.test.js +8 -1
  30. package/dist/mcp/elicitation.test.js.map +1 -1
  31. package/dist/mcp/mcp-client.d.ts +6 -10
  32. package/dist/mcp/mcp-client.d.ts.map +1 -1
  33. package/dist/mcp/mcp-client.js.map +1 -1
  34. package/dist/mcp/mcp-hooks.d.ts +12 -60
  35. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  36. package/dist/mcp/mcp-hooks.js +90 -10
  37. package/dist/mcp/mcp-hooks.js.map +1 -1
  38. package/dist/mcp/mcp-hooks.test.js +423 -0
  39. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  40. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  41. package/dist/mcp/tambo-mcp-provider.js +3 -0
  42. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  43. package/dist/mcp/tambo-mcp-provider.test.js +37 -0
  44. package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
  45. package/dist/model/component-metadata.d.ts +53 -20
  46. package/dist/model/component-metadata.d.ts.map +1 -1
  47. package/dist/model/component-metadata.js.map +1 -1
  48. package/dist/model/tambo-interactable.d.ts +6 -0
  49. package/dist/model/tambo-interactable.d.ts.map +1 -1
  50. package/dist/model/tambo-interactable.js.map +1 -1
  51. package/dist/providers/index.d.ts +1 -1
  52. package/dist/providers/index.d.ts.map +1 -1
  53. package/dist/providers/index.js.map +1 -1
  54. package/dist/providers/tambo-client-provider.d.ts +8 -0
  55. package/dist/providers/tambo-client-provider.d.ts.map +1 -1
  56. package/dist/providers/tambo-client-provider.js +10 -11
  57. package/dist/providers/tambo-client-provider.js.map +1 -1
  58. package/dist/providers/tambo-client-provider.test.d.ts +2 -0
  59. package/dist/providers/tambo-client-provider.test.d.ts.map +1 -0
  60. package/dist/providers/tambo-client-provider.test.js +208 -0
  61. package/dist/providers/tambo-client-provider.test.js.map +1 -0
  62. package/dist/providers/tambo-context-attachment-provider.d.ts +34 -92
  63. package/dist/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  64. package/dist/providers/tambo-context-attachment-provider.js +62 -105
  65. package/dist/providers/tambo-context-attachment-provider.js.map +1 -1
  66. package/dist/providers/tambo-context-attachment-provider.test.js +229 -463
  67. package/dist/providers/tambo-context-attachment-provider.test.js.map +1 -1
  68. package/dist/providers/tambo-interactable-provider.d.ts +2 -0
  69. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  70. package/dist/providers/tambo-interactable-provider.js +29 -4
  71. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  72. package/dist/providers/tambo-interactable-provider.test.js +1 -1
  73. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  74. package/dist/providers/tambo-interactables-additional-context.test.js +2 -5
  75. package/dist/providers/tambo-interactables-additional-context.test.js.map +1 -1
  76. package/dist/providers/tambo-provider.d.ts +2 -3
  77. package/dist/providers/tambo-provider.d.ts.map +1 -1
  78. package/dist/providers/tambo-provider.js +5 -6
  79. package/dist/providers/tambo-provider.js.map +1 -1
  80. package/dist/providers/tambo-registry-provider.test.js +16 -0
  81. package/dist/providers/tambo-registry-provider.test.js.map +1 -1
  82. package/dist/providers/tambo-registry-schema-compat.test.js +31 -0
  83. package/dist/providers/tambo-registry-schema-compat.test.js.map +1 -1
  84. package/dist/providers/tambo-thread-input-provider.d.ts +1 -1
  85. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  86. package/dist/providers/tambo-thread-input-provider.js +5 -1
  87. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  88. package/dist/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  89. package/dist/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  90. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  91. package/dist/providers/tambo-thread-provider.js +56 -43
  92. package/dist/providers/tambo-thread-provider.js.map +1 -1
  93. package/dist/providers/tambo-thread-provider.test.js +456 -262
  94. package/dist/providers/tambo-thread-provider.test.js.map +1 -1
  95. package/dist/schema/json-schema.js +29 -29
  96. package/dist/schema/json-schema.js.map +1 -1
  97. package/dist/schema/schema.test.js +237 -0
  98. package/dist/schema/schema.test.js.map +1 -1
  99. package/dist/schema/standard-schema.d.ts +1 -0
  100. package/dist/schema/standard-schema.d.ts.map +1 -1
  101. package/dist/schema/standard-schema.js +18 -13
  102. package/dist/schema/standard-schema.js.map +1 -1
  103. package/dist/schema/standard-schema.test.d.ts +2 -0
  104. package/dist/schema/standard-schema.test.d.ts.map +1 -0
  105. package/dist/schema/standard-schema.test.js +165 -0
  106. package/dist/schema/standard-schema.test.js.map +1 -0
  107. package/dist/schema/validate.test.js +149 -0
  108. package/dist/schema/validate.test.js.map +1 -1
  109. package/dist/schema/zod.d.ts +7 -4
  110. package/dist/schema/zod.d.ts.map +1 -1
  111. package/dist/schema/zod.js +65 -22
  112. package/dist/schema/zod.js.map +1 -1
  113. package/dist/schema/zod.test.js +112 -0
  114. package/dist/schema/zod.test.js.map +1 -1
  115. package/dist/testing/tools.d.ts +4 -1
  116. package/dist/testing/tools.d.ts.map +1 -1
  117. package/dist/testing/tools.js +6 -1
  118. package/dist/testing/tools.js.map +1 -1
  119. package/dist/util/generate-component.d.ts.map +1 -1
  120. package/dist/util/generate-component.js +18 -3
  121. package/dist/util/generate-component.js.map +1 -1
  122. package/dist/util/generate-component.test.d.ts +2 -0
  123. package/dist/util/generate-component.test.d.ts.map +1 -0
  124. package/dist/util/generate-component.test.js +340 -0
  125. package/dist/util/generate-component.test.js.map +1 -0
  126. package/dist/util/is-promise.d.ts +9 -0
  127. package/dist/util/is-promise.d.ts.map +1 -0
  128. package/dist/util/is-promise.js +20 -0
  129. package/dist/util/is-promise.js.map +1 -0
  130. package/dist/util/is-promise.test.d.ts +2 -0
  131. package/dist/util/is-promise.test.d.ts.map +1 -0
  132. package/dist/util/is-promise.test.js +48 -0
  133. package/dist/util/is-promise.test.js.map +1 -0
  134. package/dist/util/query-utils.test.d.ts +2 -0
  135. package/dist/util/query-utils.test.d.ts.map +1 -0
  136. package/dist/util/query-utils.test.js +382 -0
  137. package/dist/util/query-utils.test.js.map +1 -0
  138. package/dist/util/registry-validators.d.ts.map +1 -1
  139. package/dist/util/registry-validators.js +7 -0
  140. package/dist/util/registry-validators.js.map +1 -1
  141. package/dist/util/registry-validators.test.js +57 -0
  142. package/dist/util/registry-validators.test.js.map +1 -1
  143. package/dist/util/registry.d.ts.map +1 -1
  144. package/dist/util/registry.js +9 -0
  145. package/dist/util/registry.js.map +1 -1
  146. package/dist/util/registry.test.js +323 -1
  147. package/dist/util/registry.test.js.map +1 -1
  148. package/dist/util/resource-validators.test.d.ts +2 -0
  149. package/dist/util/resource-validators.test.d.ts.map +1 -0
  150. package/dist/util/resource-validators.test.js +90 -0
  151. package/dist/util/resource-validators.test.js.map +1 -0
  152. package/dist/util/tool-caller.d.ts +2 -2
  153. package/dist/util/tool-caller.d.ts.map +1 -1
  154. package/dist/util/tool-caller.js +8 -8
  155. package/dist/util/tool-caller.js.map +1 -1
  156. package/dist/util/validate-component-name.test.d.ts +2 -0
  157. package/dist/util/validate-component-name.test.d.ts.map +1 -0
  158. package/dist/util/validate-component-name.test.js +35 -0
  159. package/dist/util/validate-component-name.test.js.map +1 -0
  160. package/esm/context-helpers/context-helpers.test.js +16 -4
  161. package/esm/context-helpers/context-helpers.test.js.map +1 -1
  162. package/esm/context-helpers/current-interactables-context-helper.d.ts +2 -2
  163. package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  164. package/esm/context-helpers/current-interactables-context-helper.js +31 -15
  165. package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
  166. package/esm/context-helpers/registry.d.ts +2 -2
  167. package/esm/context-helpers/registry.d.ts.map +1 -1
  168. package/esm/context-helpers/registry.js.map +1 -1
  169. package/esm/context-helpers/types.d.ts +2 -2
  170. package/esm/context-helpers/types.d.ts.map +1 -1
  171. package/esm/context-helpers/types.js.map +1 -1
  172. package/esm/hooks/use-message-images.test.js +174 -37
  173. package/esm/hooks/use-message-images.test.js.map +1 -1
  174. package/esm/hooks/use-tambo-voice.d.ts +1 -1
  175. package/esm/hooks/use-tambo-voice.js +1 -1
  176. package/esm/hooks/use-tambo-voice.js.map +1 -1
  177. package/esm/hooks/use-tambo-voice.test.d.ts +2 -0
  178. package/esm/hooks/use-tambo-voice.test.d.ts.map +1 -0
  179. package/esm/hooks/use-tambo-voice.test.js +234 -0
  180. package/esm/hooks/use-tambo-voice.test.js.map +1 -0
  181. package/esm/index.d.ts +2 -2
  182. package/esm/index.d.ts.map +1 -1
  183. package/esm/index.js.map +1 -1
  184. package/esm/mcp/elicitation.d.ts.map +1 -1
  185. package/esm/mcp/elicitation.js +12 -0
  186. package/esm/mcp/elicitation.js.map +1 -1
  187. package/esm/mcp/elicitation.test.js +8 -1
  188. package/esm/mcp/elicitation.test.js.map +1 -1
  189. package/esm/mcp/mcp-client.d.ts +6 -10
  190. package/esm/mcp/mcp-client.d.ts.map +1 -1
  191. package/esm/mcp/mcp-client.js.map +1 -1
  192. package/esm/mcp/mcp-hooks.d.ts +12 -60
  193. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  194. package/esm/mcp/mcp-hooks.js +57 -10
  195. package/esm/mcp/mcp-hooks.js.map +1 -1
  196. package/esm/mcp/mcp-hooks.test.js +423 -0
  197. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  198. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  199. package/esm/mcp/tambo-mcp-provider.js +3 -0
  200. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  201. package/esm/mcp/tambo-mcp-provider.test.js +37 -0
  202. package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
  203. package/esm/model/component-metadata.d.ts +53 -20
  204. package/esm/model/component-metadata.d.ts.map +1 -1
  205. package/esm/model/component-metadata.js.map +1 -1
  206. package/esm/model/tambo-interactable.d.ts +6 -0
  207. package/esm/model/tambo-interactable.d.ts.map +1 -1
  208. package/esm/model/tambo-interactable.js.map +1 -1
  209. package/esm/providers/index.d.ts +1 -1
  210. package/esm/providers/index.d.ts.map +1 -1
  211. package/esm/providers/index.js.map +1 -1
  212. package/esm/providers/tambo-client-provider.d.ts +8 -0
  213. package/esm/providers/tambo-client-provider.d.ts.map +1 -1
  214. package/esm/providers/tambo-client-provider.js +11 -12
  215. package/esm/providers/tambo-client-provider.js.map +1 -1
  216. package/esm/providers/tambo-client-provider.test.d.ts +2 -0
  217. package/esm/providers/tambo-client-provider.test.d.ts.map +1 -0
  218. package/esm/providers/tambo-client-provider.test.js +203 -0
  219. package/esm/providers/tambo-client-provider.test.js.map +1 -0
  220. package/esm/providers/tambo-context-attachment-provider.d.ts +34 -92
  221. package/esm/providers/tambo-context-attachment-provider.d.ts.map +1 -1
  222. package/esm/providers/tambo-context-attachment-provider.js +63 -106
  223. package/esm/providers/tambo-context-attachment-provider.js.map +1 -1
  224. package/esm/providers/tambo-context-attachment-provider.test.js +230 -464
  225. package/esm/providers/tambo-context-attachment-provider.test.js.map +1 -1
  226. package/esm/providers/tambo-interactable-provider.d.ts +2 -0
  227. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  228. package/esm/providers/tambo-interactable-provider.js +29 -4
  229. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  230. package/esm/providers/tambo-interactable-provider.test.js +1 -1
  231. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  232. package/esm/providers/tambo-interactables-additional-context.test.js +2 -5
  233. package/esm/providers/tambo-interactables-additional-context.test.js.map +1 -1
  234. package/esm/providers/tambo-provider.d.ts +2 -3
  235. package/esm/providers/tambo-provider.d.ts.map +1 -1
  236. package/esm/providers/tambo-provider.js +5 -6
  237. package/esm/providers/tambo-provider.js.map +1 -1
  238. package/esm/providers/tambo-registry-provider.test.js +16 -0
  239. package/esm/providers/tambo-registry-provider.test.js.map +1 -1
  240. package/esm/providers/tambo-registry-schema-compat.test.js +31 -0
  241. package/esm/providers/tambo-registry-schema-compat.test.js.map +1 -1
  242. package/esm/providers/tambo-thread-input-provider.d.ts +1 -1
  243. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  244. package/esm/providers/tambo-thread-input-provider.js +5 -1
  245. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  246. package/esm/providers/tambo-thread-provider-initial-messages.test.js +84 -2
  247. package/esm/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  248. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  249. package/esm/providers/tambo-thread-provider.js +56 -43
  250. package/esm/providers/tambo-thread-provider.js.map +1 -1
  251. package/esm/providers/tambo-thread-provider.test.js +456 -262
  252. package/esm/providers/tambo-thread-provider.test.js.map +1 -1
  253. package/esm/schema/json-schema.js +1 -1
  254. package/esm/schema/json-schema.js.map +1 -1
  255. package/esm/schema/schema.test.js +238 -1
  256. package/esm/schema/schema.test.js.map +1 -1
  257. package/esm/schema/standard-schema.d.ts +1 -0
  258. package/esm/schema/standard-schema.d.ts.map +1 -1
  259. package/esm/schema/standard-schema.js +18 -13
  260. package/esm/schema/standard-schema.js.map +1 -1
  261. package/esm/schema/standard-schema.test.d.ts +2 -0
  262. package/esm/schema/standard-schema.test.d.ts.map +1 -0
  263. package/esm/schema/standard-schema.test.js +130 -0
  264. package/esm/schema/standard-schema.test.js.map +1 -0
  265. package/esm/schema/validate.test.js +149 -0
  266. package/esm/schema/validate.test.js.map +1 -1
  267. package/esm/schema/zod.d.ts +7 -4
  268. package/esm/schema/zod.d.ts.map +1 -1
  269. package/esm/schema/zod.js +65 -22
  270. package/esm/schema/zod.js.map +1 -1
  271. package/esm/schema/zod.test.js +113 -1
  272. package/esm/schema/zod.test.js.map +1 -1
  273. package/esm/testing/tools.d.ts +4 -1
  274. package/esm/testing/tools.d.ts.map +1 -1
  275. package/esm/testing/tools.js +6 -1
  276. package/esm/testing/tools.js.map +1 -1
  277. package/esm/util/generate-component.d.ts.map +1 -1
  278. package/esm/util/generate-component.js +18 -3
  279. package/esm/util/generate-component.js.map +1 -1
  280. package/esm/util/generate-component.test.d.ts +2 -0
  281. package/esm/util/generate-component.test.d.ts.map +1 -0
  282. package/esm/util/generate-component.test.js +302 -0
  283. package/esm/util/generate-component.test.js.map +1 -0
  284. package/esm/util/is-promise.d.ts +9 -0
  285. package/esm/util/is-promise.d.ts.map +1 -0
  286. package/esm/util/is-promise.js +17 -0
  287. package/esm/util/is-promise.js.map +1 -0
  288. package/esm/util/is-promise.test.d.ts +2 -0
  289. package/esm/util/is-promise.test.d.ts.map +1 -0
  290. package/esm/util/is-promise.test.js +46 -0
  291. package/esm/util/is-promise.test.js.map +1 -0
  292. package/esm/util/query-utils.test.d.ts +2 -0
  293. package/esm/util/query-utils.test.d.ts.map +1 -0
  294. package/esm/util/query-utils.test.js +380 -0
  295. package/esm/util/query-utils.test.js.map +1 -0
  296. package/esm/util/registry-validators.d.ts.map +1 -1
  297. package/esm/util/registry-validators.js +7 -0
  298. package/esm/util/registry-validators.js.map +1 -1
  299. package/esm/util/registry-validators.test.js +57 -0
  300. package/esm/util/registry-validators.test.js.map +1 -1
  301. package/esm/util/registry.d.ts.map +1 -1
  302. package/esm/util/registry.js +9 -0
  303. package/esm/util/registry.js.map +1 -1
  304. package/esm/util/registry.test.js +324 -2
  305. package/esm/util/registry.test.js.map +1 -1
  306. package/esm/util/resource-validators.test.d.ts +2 -0
  307. package/esm/util/resource-validators.test.d.ts.map +1 -0
  308. package/esm/util/resource-validators.test.js +88 -0
  309. package/esm/util/resource-validators.test.js.map +1 -0
  310. package/esm/util/tool-caller.d.ts +2 -2
  311. package/esm/util/tool-caller.d.ts.map +1 -1
  312. package/esm/util/tool-caller.js +8 -8
  313. package/esm/util/tool-caller.js.map +1 -1
  314. package/esm/util/validate-component-name.test.d.ts +2 -0
  315. package/esm/util/validate-component-name.test.d.ts.map +1 -0
  316. package/esm/util/validate-component-name.test.js +33 -0
  317. package/esm/util/validate-component-name.test.js.map +1 -0
  318. package/package.json +15 -23
  319. package/dist/schema/alias.d.ts +0 -3
  320. package/dist/schema/alias.d.ts.map +0 -1
  321. package/dist/schema/alias.js +0 -6
  322. package/dist/schema/alias.js.map +0 -1
  323. package/esm/schema/alias.d.ts +0 -3
  324. package/esm/schema/alias.d.ts.map +0 -1
  325. package/esm/schema/alias.js +0 -13
  326. package/esm/schema/alias.js.map +0 -1
@@ -0,0 +1,203 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import React from "react";
3
+ import { TamboClientProvider, useIsTamboTokenUpdating, useTamboClient, useTamboQueryClient, } from "./tambo-client-provider";
4
+ // Mock the session token hook to control token fetching state
5
+ jest.mock("./hooks/use-tambo-session-token", () => ({
6
+ useTamboSessionToken: jest.fn(),
7
+ }));
8
+ import { useTamboSessionToken } from "./hooks/use-tambo-session-token";
9
+ // Add fetch polyfill for jsdom environment (TamboAI SDK requires it)
10
+ const mockFetch = jest.fn();
11
+ let previousFetch;
12
+ beforeEach(() => {
13
+ mockFetch.mockReset();
14
+ previousFetch = global.fetch;
15
+ global.fetch = mockFetch;
16
+ });
17
+ afterEach(() => {
18
+ global.fetch = previousFetch;
19
+ });
20
+ describe("TamboClientProvider", () => {
21
+ beforeEach(() => {
22
+ jest.clearAllMocks();
23
+ // Default mock: not fetching
24
+ jest.mocked(useTamboSessionToken).mockReturnValue({
25
+ isFetching: false,
26
+ data: undefined,
27
+ error: null,
28
+ isLoading: false,
29
+ isError: false,
30
+ isSuccess: false,
31
+ status: "pending",
32
+ fetchStatus: "idle",
33
+ });
34
+ });
35
+ const createWrapper = (props) => {
36
+ const Wrapper = ({ children }) => (React.createElement(TamboClientProvider, { ...props }, children));
37
+ Wrapper.displayName = "TestWrapper";
38
+ return Wrapper;
39
+ };
40
+ describe("Client Configuration", () => {
41
+ it("should create client accessible via useTamboClient hook", () => {
42
+ const { result } = renderHook(() => useTamboClient(), {
43
+ wrapper: createWrapper({ apiKey: "test-api-key" }),
44
+ });
45
+ // Client should be a TamboAI instance with expected shape
46
+ expect(result.current).toBeDefined();
47
+ expect(result.current.beta).toBeDefined();
48
+ });
49
+ it("should provide the same client instance on re-renders", () => {
50
+ const { result, rerender } = renderHook(() => useTamboClient(), {
51
+ wrapper: createWrapper({ apiKey: "test-api-key" }),
52
+ });
53
+ const firstClient = result.current;
54
+ rerender();
55
+ const secondClient = result.current;
56
+ expect(firstClient).toBe(secondClient);
57
+ });
58
+ it("should configure client with provided tamboUrl", () => {
59
+ const { result } = renderHook(() => useTamboClient(), {
60
+ wrapper: createWrapper({
61
+ apiKey: "test-api-key",
62
+ tamboUrl: "https://custom.tambo.api",
63
+ }),
64
+ });
65
+ expect(result.current.baseURL).toBe("https://custom.tambo.api");
66
+ });
67
+ it("should configure client with provided environment", async () => {
68
+ const { result } = renderHook(() => useTamboClient(), {
69
+ wrapper: createWrapper({
70
+ apiKey: "test-api-key",
71
+ environment: "staging",
72
+ }),
73
+ });
74
+ const { url } = await result.current.buildRequest({
75
+ method: "get",
76
+ path: "/test-endpoint",
77
+ });
78
+ expect(url).toBe("https://hydra-api-dev.up.railway.app/test-endpoint");
79
+ });
80
+ it("should throw if both tamboUrl and environment are provided", () => {
81
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
82
+ expect(() => {
83
+ renderHook(() => useTamboClient(), {
84
+ wrapper: createWrapper({
85
+ apiKey: "test-api-key",
86
+ tamboUrl: "https://custom.tambo.api",
87
+ environment: "staging",
88
+ }),
89
+ });
90
+ }).toThrow("Ambiguous URL; The `baseURL` option (or TAMBO_AI_BASE_URL env var) and the `environment` option are given. If you want to use the environment you must pass baseURL: null");
91
+ consoleSpy.mockRestore();
92
+ });
93
+ it("should include additional headers in client configuration", async () => {
94
+ const { result } = renderHook(() => useTamboClient(), {
95
+ wrapper: createWrapper({
96
+ apiKey: "test-api-key",
97
+ additionalHeaders: {
98
+ "X-Custom-Header": "custom-value",
99
+ "X-Another-Header": "another-value",
100
+ },
101
+ }),
102
+ });
103
+ const { req } = await result.current.buildRequest({
104
+ method: "get",
105
+ path: "/test-endpoint",
106
+ });
107
+ expect(req.headers.get("X-Tambo-React-Version")).toBeDefined();
108
+ expect(req.headers.get("X-Tambo-React-Version")).toMatch(/\d+\.\d+\.\d+/); // version format
109
+ expect(req.headers.get("X-Custom-Header")).toBe("custom-value");
110
+ expect(req.headers.get("X-Another-Header")).toBe("another-value");
111
+ });
112
+ });
113
+ describe("Token State", () => {
114
+ it("should expose isUpdatingToken=true when session token is fetching", () => {
115
+ jest.mocked(useTamboSessionToken).mockReturnValue({
116
+ isFetching: true,
117
+ });
118
+ const { result } = renderHook(() => useIsTamboTokenUpdating(), {
119
+ wrapper: createWrapper({
120
+ apiKey: "test-api-key",
121
+ userToken: "oauth-token",
122
+ }),
123
+ });
124
+ expect(result.current).toBe(true);
125
+ });
126
+ it("should expose isUpdatingToken=false when not fetching", () => {
127
+ jest.mocked(useTamboSessionToken).mockReturnValue({
128
+ isFetching: false,
129
+ });
130
+ const { result } = renderHook(() => useIsTamboTokenUpdating(), {
131
+ wrapper: createWrapper({ apiKey: "test-api-key" }),
132
+ });
133
+ expect(result.current).toBe(false);
134
+ });
135
+ it("should call useTamboSessionToken with userToken when provided", () => {
136
+ renderHook(() => useTamboClient(), {
137
+ wrapper: createWrapper({
138
+ apiKey: "test-api-key",
139
+ userToken: "my-oauth-token",
140
+ }),
141
+ });
142
+ expect(useTamboSessionToken).toHaveBeenCalledWith(expect.anything(), // client
143
+ expect.anything(), // queryClient
144
+ "my-oauth-token");
145
+ });
146
+ });
147
+ });
148
+ describe("Hook Contracts", () => {
149
+ beforeEach(() => {
150
+ jest.clearAllMocks();
151
+ jest.mocked(useTamboSessionToken).mockReturnValue({
152
+ isFetching: false,
153
+ });
154
+ });
155
+ const createWrapper = (props) => {
156
+ const Wrapper = ({ children }) => (React.createElement(TamboClientProvider, { ...props }, children));
157
+ Wrapper.displayName = "TestWrapper";
158
+ return Wrapper;
159
+ };
160
+ describe("useTamboClient", () => {
161
+ it("should return client instance inside provider", () => {
162
+ const { result } = renderHook(() => useTamboClient(), {
163
+ wrapper: createWrapper({ apiKey: "test-api-key" }),
164
+ });
165
+ expect(result.current).toBeDefined();
166
+ expect(result.current.beta).toBeDefined();
167
+ });
168
+ it("should throw descriptive error outside provider", () => {
169
+ // Suppress console.error for this test
170
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
171
+ expect(() => {
172
+ renderHook(() => useTamboClient());
173
+ }).toThrow("useTamboClient must be used within a TamboClientProvider");
174
+ consoleSpy.mockRestore();
175
+ });
176
+ });
177
+ describe("useTamboQueryClient", () => {
178
+ it("should return QueryClient instance inside provider", () => {
179
+ const { result } = renderHook(() => useTamboQueryClient(), {
180
+ wrapper: createWrapper({ apiKey: "test-api-key" }),
181
+ });
182
+ expect(result.current).toBeDefined();
183
+ expect(typeof result.current.getQueryCache).toBe("function");
184
+ });
185
+ it("should throw descriptive error outside provider", () => {
186
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
187
+ expect(() => {
188
+ renderHook(() => useTamboQueryClient());
189
+ }).toThrow("useTamboQueryClient must be used within a TamboClientProvider");
190
+ consoleSpy.mockRestore();
191
+ });
192
+ });
193
+ describe("useIsTamboTokenUpdating", () => {
194
+ it("should throw descriptive error outside provider", () => {
195
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
196
+ expect(() => {
197
+ renderHook(() => useIsTamboTokenUpdating());
198
+ }).toThrow("useIsTamboTokenUpdating must be used within a TamboClientProvider");
199
+ consoleSpy.mockRestore();
200
+ });
201
+ });
202
+ });
203
+ //# sourceMappingURL=tambo-client-provider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tambo-client-provider.test.js","sourceRoot":"","sources":["../../src/providers/tambo-client-provider.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport {\n TamboClientProvider,\n TamboClientProviderProps,\n useIsTamboTokenUpdating,\n useTamboClient,\n useTamboQueryClient,\n} from \"./tambo-client-provider\";\n\n// Mock the session token hook to control token fetching state\njest.mock(\"./hooks/use-tambo-session-token\", () => ({\n useTamboSessionToken: jest.fn(),\n}));\n\nimport { useTamboSessionToken } from \"./hooks/use-tambo-session-token\";\n\n// Add fetch polyfill for jsdom environment (TamboAI SDK requires it)\nconst mockFetch = jest.fn();\nlet previousFetch: typeof fetch;\n\nbeforeEach(() => {\n mockFetch.mockReset();\n previousFetch = global.fetch;\n global.fetch = mockFetch as unknown as typeof fetch;\n});\n\nafterEach(() => {\n global.fetch = previousFetch;\n});\n\ndescribe(\"TamboClientProvider\", () => {\n beforeEach(() => {\n jest.clearAllMocks();\n\n // Default mock: not fetching\n jest.mocked(useTamboSessionToken).mockReturnValue({\n isFetching: false,\n data: undefined,\n error: null,\n isLoading: false,\n isError: false,\n isSuccess: false,\n status: \"pending\",\n fetchStatus: \"idle\",\n } as any);\n });\n\n const createWrapper = (props: TamboClientProviderProps) => {\n const Wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboClientProvider {...props}>{children}</TamboClientProvider>\n );\n Wrapper.displayName = \"TestWrapper\";\n return Wrapper;\n };\n\n describe(\"Client Configuration\", () => {\n it(\"should create client accessible via useTamboClient hook\", () => {\n const { result } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({ apiKey: \"test-api-key\" }),\n });\n\n // Client should be a TamboAI instance with expected shape\n expect(result.current).toBeDefined();\n expect(result.current.beta).toBeDefined();\n });\n\n it(\"should provide the same client instance on re-renders\", () => {\n const { result, rerender } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({ apiKey: \"test-api-key\" }),\n });\n\n const firstClient = result.current;\n rerender();\n const secondClient = result.current;\n\n expect(firstClient).toBe(secondClient);\n });\n\n it(\"should configure client with provided tamboUrl\", () => {\n const { result } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n tamboUrl: \"https://custom.tambo.api\",\n }),\n });\n\n expect(result.current.baseURL).toBe(\"https://custom.tambo.api\");\n });\n\n it(\"should configure client with provided environment\", async () => {\n const { result } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n environment: \"staging\",\n }),\n });\n\n const { url } = await result.current.buildRequest({\n method: \"get\",\n path: \"/test-endpoint\",\n });\n\n expect(url).toBe(\"https://hydra-api-dev.up.railway.app/test-endpoint\");\n });\n\n it(\"should throw if both tamboUrl and environment are provided\", () => {\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => {\n renderHook(() => useTamboClient(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n tamboUrl: \"https://custom.tambo.api\",\n environment: \"staging\",\n }),\n });\n }).toThrow(\n \"Ambiguous URL; The `baseURL` option (or TAMBO_AI_BASE_URL env var) and the `environment` option are given. If you want to use the environment you must pass baseURL: null\",\n );\n\n consoleSpy.mockRestore();\n });\n\n it(\"should include additional headers in client configuration\", async () => {\n const { result } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n additionalHeaders: {\n \"X-Custom-Header\": \"custom-value\",\n \"X-Another-Header\": \"another-value\",\n },\n }),\n });\n\n const { req } = await result.current.buildRequest({\n method: \"get\",\n path: \"/test-endpoint\",\n });\n\n expect(req.headers.get(\"X-Tambo-React-Version\")).toBeDefined();\n expect(req.headers.get(\"X-Tambo-React-Version\")).toMatch(/\\d+\\.\\d+\\.\\d+/); // version format\n expect(req.headers.get(\"X-Custom-Header\")).toBe(\"custom-value\");\n expect(req.headers.get(\"X-Another-Header\")).toBe(\"another-value\");\n });\n });\n\n describe(\"Token State\", () => {\n it(\"should expose isUpdatingToken=true when session token is fetching\", () => {\n jest.mocked(useTamboSessionToken).mockReturnValue({\n isFetching: true,\n } as any);\n\n const { result } = renderHook(() => useIsTamboTokenUpdating(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n userToken: \"oauth-token\",\n }),\n });\n\n expect(result.current).toBe(true);\n });\n\n it(\"should expose isUpdatingToken=false when not fetching\", () => {\n jest.mocked(useTamboSessionToken).mockReturnValue({\n isFetching: false,\n } as any);\n\n const { result } = renderHook(() => useIsTamboTokenUpdating(), {\n wrapper: createWrapper({ apiKey: \"test-api-key\" }),\n });\n\n expect(result.current).toBe(false);\n });\n\n it(\"should call useTamboSessionToken with userToken when provided\", () => {\n renderHook(() => useTamboClient(), {\n wrapper: createWrapper({\n apiKey: \"test-api-key\",\n userToken: \"my-oauth-token\",\n }),\n });\n\n expect(useTamboSessionToken).toHaveBeenCalledWith(\n expect.anything(), // client\n expect.anything(), // queryClient\n \"my-oauth-token\",\n );\n });\n });\n});\n\ndescribe(\"Hook Contracts\", () => {\n beforeEach(() => {\n jest.clearAllMocks();\n\n jest.mocked(useTamboSessionToken).mockReturnValue({\n isFetching: false,\n } as any);\n });\n\n const createWrapper = (props: { apiKey: string }) => {\n const Wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboClientProvider {...props}>{children}</TamboClientProvider>\n );\n Wrapper.displayName = \"TestWrapper\";\n return Wrapper;\n };\n\n describe(\"useTamboClient\", () => {\n it(\"should return client instance inside provider\", () => {\n const { result } = renderHook(() => useTamboClient(), {\n wrapper: createWrapper({ apiKey: \"test-api-key\" }),\n });\n\n expect(result.current).toBeDefined();\n expect(result.current.beta).toBeDefined();\n });\n\n it(\"should throw descriptive error outside provider\", () => {\n // Suppress console.error for this test\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => {\n renderHook(() => useTamboClient());\n }).toThrow(\"useTamboClient must be used within a TamboClientProvider\");\n\n consoleSpy.mockRestore();\n });\n });\n\n describe(\"useTamboQueryClient\", () => {\n it(\"should return QueryClient instance inside provider\", () => {\n const { result } = renderHook(() => useTamboQueryClient(), {\n wrapper: createWrapper({ apiKey: \"test-api-key\" }),\n });\n\n expect(result.current).toBeDefined();\n expect(typeof result.current.getQueryCache).toBe(\"function\");\n });\n\n it(\"should throw descriptive error outside provider\", () => {\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => {\n renderHook(() => useTamboQueryClient());\n }).toThrow(\n \"useTamboQueryClient must be used within a TamboClientProvider\",\n );\n\n consoleSpy.mockRestore();\n });\n });\n\n describe(\"useIsTamboTokenUpdating\", () => {\n it(\"should throw descriptive error outside provider\", () => {\n const consoleSpy = jest.spyOn(console, \"error\").mockImplementation();\n\n expect(() => {\n renderHook(() => useIsTamboTokenUpdating());\n }).toThrow(\n \"useIsTamboTokenUpdating must be used within a TamboClientProvider\",\n );\n\n consoleSpy.mockRestore();\n });\n });\n});\n"]}
@@ -1,110 +1,52 @@
1
- import type { Suggestion } from "@tambo-ai/typescript-sdk/resources/beta/threads/suggestions";
2
1
  import React from "react";
3
2
  /**
4
- * Represents a context attachment that can be displayed in MessageInputContexts.
5
- * Context attachments appear as badges above the message input and provide additional
6
- * information to the AI about what to focus on.
7
- * @property {string} name - Display name shown in the badge
8
- * @property {React.ReactNode} [icon] - Optional icon to display in the badge
9
- * @property {Record<string, unknown>} [metadata] - Additional data passed to the AI
10
- * @example
11
- * ```tsx
12
- * const context: ContextAttachment = {
13
- * name: "Button.tsx",
14
- * icon: <FileIcon />,
15
- * metadata: { filePath: "/src/components/Button.tsx" }
16
- * };
17
- * ```
3
+ * Represents a context attachment that will be sent with the next user message.
4
+ * These are automatically registered as context helpers and will be included in
5
+ * the additionalContext when the next message is sent.
6
+ * @property {string} id - Unique identifier for this context attachment
7
+ * @property {string} [displayName] - Optional display name for UI rendering
8
+ * @property {string} context - The context value that will be used in additionalContext
9
+ * @property {string} [type] - Optional type identifier for grouping/rendering multiple contexts of the same type
18
10
  */
19
11
  export interface ContextAttachment {
20
12
  id: string;
21
- name: string;
22
- icon?: React.ReactNode;
23
- metadata?: Record<string, unknown>;
13
+ displayName?: string;
14
+ context: string;
15
+ type?: string;
24
16
  }
25
17
  /**
26
- * Represents the data structure returned by a context helper
27
- */
28
- export type ContextHelperData = Record<string, unknown>;
29
- /**
30
- * Context state interface for managing context attachments and custom suggestions.
31
- * @property {ContextAttachment[]} attachments - Array of active context attachments (badges above message input)
32
- * @property {(context: Omit<ContextAttachment, "id">) => void} addContextAttachment - Add a new context attachment
18
+ * Context state interface for managing context attachments.
19
+ * @property {ContextAttachment[]} attachments - Array of active context attachments
20
+ * @property {(contextAttachment: Omit<ContextAttachment, "id">) => ContextAttachment} addContextAttachment - Add a new context attachment, returns the attachment
33
21
  * @property {(id: string) => void} removeContextAttachment - Remove a context attachment by ID
34
- * @property {() => void} clearContextAttachments - Remove all context attachments - This is used to clear the context when the user submits a message
35
- * @property {Suggestion[] | null} customSuggestions - Custom suggestions to display instead of auto-generated ones
36
- * @property {(suggestions: Suggestion[] | null) => void} setCustomSuggestions - Set or clear custom suggestions
22
+ * @property {() => void} clearContextAttachments - Remove all context attachments
37
23
  */
38
24
  export interface ContextAttachmentState {
39
25
  attachments: ContextAttachment[];
40
- addContextAttachment: (context: Omit<ContextAttachment, "id">) => void;
26
+ addContextAttachment: (contextAttachment: Omit<ContextAttachment, "id">) => ContextAttachment;
41
27
  removeContextAttachment: (id: string) => void;
42
28
  clearContextAttachments: () => void;
43
- customSuggestions: Suggestion[] | null;
44
- setCustomSuggestions: (suggestions: Suggestion[] | null) => void;
45
29
  }
46
- /**
47
- * Props for the TamboContextAttachmentProvider.
48
- * @property {(context: ContextAttachment) => Promise<ContextHelperData> | ContextHelperData} [getContextHelperData] - Optional function to customize the data sent to the AI for each context. If not provided, uses a default structure with the context name and instruction.
49
- * @example
50
- * ```tsx
51
- * <TamboContextAttachmentProvider
52
- * getContextHelperData={(context) => ({
53
- * selectedFile: {
54
- * name: context.name,
55
- * path: context.metadata?.filePath,
56
- * instruction: "Focus on this file"
57
- * }
58
- * })}
59
- * >
60
- * {children}
61
- * </TamboContextAttachmentProvider>
62
- * ```
63
- */
64
30
  export interface TamboContextAttachmentProviderProps {
65
31
  children?: React.ReactNode;
66
- getContextHelperData?: (context: ContextAttachment) => Promise<ContextHelperData> | ContextHelperData;
67
32
  }
68
33
  /**
69
- * Provider that enables context attachment features and custom suggestions in MessageInput.
70
- * **When to use:**
34
+ * Provider that manages context attachments for the next user message.
71
35
  * - **Included by default** in TamboProvider - no need to wrap separately
72
36
  * - Use `useTamboContextAttachment()` hook to manage context attachments
73
37
  * **What it does:**
74
- * - Manages context items that appear as badges above MessageInput
75
- * - Syncs context data with Tambo's AI for better responses
76
- * - Manages custom suggestions that replace auto-generated suggestions
77
- * - Allows components to add/remove contexts via `useTamboContextAttachment()`
78
- * - Allows components to set custom suggestions via `setCustomSuggestions()`
38
+ * - Stores context attachments that will be sent with the next message
39
+ * - Automatically registers/deregisters context helpers for each attachment
40
+ * - Context helpers are automatically collected during message submission
41
+ * - Context attachments are cleared after message submission (one-time use)
42
+ *
43
+ * **Note:** Context attachments are automatically included in additionalContext when
44
+ * the next message is sent. They are cleared after submission.
79
45
  * @param props - The props for the TamboContextAttachmentProvider
80
46
  * @param props.children - The children to wrap
81
- * @param props.getContextHelperData - The function to get the context helper data
82
47
  * @returns The TamboContextAttachmentProvider component
83
- * @example
84
- * Basic usage - already included in TamboProvider
85
- * ```tsx
86
- * <TamboProvider apiKey="...">
87
- * <App />
88
- * </TamboProvider>
89
- * ```
90
- * @example
91
- * Using TamboProvider with custom context data
92
- * ```tsx
93
- * <TamboProvider
94
- * apiKey="..."
95
- * getContextHelperData={(context) => ({
96
- * selectedComponent: {
97
- * name: context.name,
98
- * filePath: context.metadata?.path,
99
- * instruction: "Edit this component"
100
- * }
101
- * })}
102
- * >
103
- * <App />
104
- * </TamboProvider>
105
- * ```
106
48
  */
107
- export declare function TamboContextAttachmentProvider({ children, getContextHelperData, }: TamboContextAttachmentProviderProps): React.JSX.Element;
49
+ export declare function TamboContextAttachmentProvider({ children, }: TamboContextAttachmentProviderProps): React.JSX.Element;
108
50
  /**
109
51
  * Hook to access context attachment state and methods.
110
52
  * **Must be used within a `TamboProvider`** - throws an error otherwise.
@@ -112,20 +54,20 @@ export declare function TamboContextAttachmentProvider({ children, getContextHel
112
54
  * @returns The context attachment state and methods
113
55
  * @example
114
56
  * ```tsx
115
- * const contextAttachment = useTamboContextAttachment();
57
+ * const { addContextAttachment, attachments, clearContextAttachments } = useTamboContextAttachment();
116
58
  *
117
- * // Add a context
118
- * contextAttachment.addContextAttachment({
119
- * name: "Button.tsx",
120
- * icon: <FileIcon />,
121
- * metadata: { path: "/src/Button.tsx" }
59
+ * // Add a context attachment for the next message
60
+ * const attachment = addContextAttachment({
61
+ * context: "The contents of File.txt",
62
+ * displayName: "File.txt", // optional
63
+ * type: "file" // optional
122
64
  * });
123
65
  *
124
- * // Remove a context
125
- * contextAttachment.removeContextAttachment(contextId);
66
+ * // Remove a context attachment
67
+ * removeContextAttachment(attachment.id);
126
68
  *
127
- * // Set custom suggestions
128
- * contextAttachment.setCustomSuggestions([{ id: "1", title: "Add Feature" }]);
69
+ * // Clear all context attachments
70
+ * clearContextAttachments();
129
71
  * ```
130
72
  */
131
73
  export declare function useTamboContextAttachment(): ContextAttachmentState;
@@ -1 +1 @@
1
- {"version":3,"file":"tambo-context-attachment-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-context-attachment-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6DAA6D,CAAC;AAC9F,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExD;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,oBAAoB,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC;IACvE,uBAAuB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,iBAAiB,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IACvC,oBAAoB,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,oBAAoB,CAAC,EAAE,CACrB,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAC;CACrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,8BAA8B,CAAC,EAC7C,QAAQ,EACR,oBAAoB,GACrB,EAAE,mCAAmC,qBAsHrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,yBAAyB,2BAQxC"}
1
+ {"version":3,"file":"tambo-context-attachment-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-context-attachment-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,oBAAoB,EAAE,CACpB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAC7C,iBAAiB,CAAC;IACvB,uBAAuB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,uBAAuB,EAAE,MAAM,IAAI,CAAC;CACrC;AAMD,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,EAC7C,QAAQ,GACT,EAAE,mCAAmC,qBAuFrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,yBAAyB,2BAQxC"}
@@ -1,117 +1,77 @@
1
1
  "use client";
2
- import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
2
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
3
3
  import { useTamboContextHelpers } from "./tambo-context-helpers-provider";
4
4
  const ContextAttachmentContext = createContext(null);
5
+ const CONTEXT_ATTACHMENTS_HELPER_KEY = "contextAttachments";
5
6
  /**
6
- * Provider that enables context attachment features and custom suggestions in MessageInput.
7
- * **When to use:**
7
+ * Provider that manages context attachments for the next user message.
8
8
  * - **Included by default** in TamboProvider - no need to wrap separately
9
9
  * - Use `useTamboContextAttachment()` hook to manage context attachments
10
10
  * **What it does:**
11
- * - Manages context items that appear as badges above MessageInput
12
- * - Syncs context data with Tambo's AI for better responses
13
- * - Manages custom suggestions that replace auto-generated suggestions
14
- * - Allows components to add/remove contexts via `useTamboContextAttachment()`
15
- * - Allows components to set custom suggestions via `setCustomSuggestions()`
11
+ * - Stores context attachments that will be sent with the next message
12
+ * - Automatically registers/deregisters context helpers for each attachment
13
+ * - Context helpers are automatically collected during message submission
14
+ * - Context attachments are cleared after message submission (one-time use)
15
+ *
16
+ * **Note:** Context attachments are automatically included in additionalContext when
17
+ * the next message is sent. They are cleared after submission.
16
18
  * @param props - The props for the TamboContextAttachmentProvider
17
19
  * @param props.children - The children to wrap
18
- * @param props.getContextHelperData - The function to get the context helper data
19
20
  * @returns The TamboContextAttachmentProvider component
20
- * @example
21
- * Basic usage - already included in TamboProvider
22
- * ```tsx
23
- * <TamboProvider apiKey="...">
24
- * <App />
25
- * </TamboProvider>
26
- * ```
27
- * @example
28
- * Using TamboProvider with custom context data
29
- * ```tsx
30
- * <TamboProvider
31
- * apiKey="..."
32
- * getContextHelperData={(context) => ({
33
- * selectedComponent: {
34
- * name: context.name,
35
- * filePath: context.metadata?.path,
36
- * instruction: "Edit this component"
37
- * }
38
- * })}
39
- * >
40
- * <App />
41
- * </TamboProvider>
42
- * ```
43
21
  */
44
- export function TamboContextAttachmentProvider({ children, getContextHelperData, }) {
45
- const [attachments, setAttachments] = useState([]);
46
- const [customSuggestions, setCustomSuggestions] = useState(null);
22
+ export function TamboContextAttachmentProvider({ children, }) {
47
23
  const { addContextHelper, removeContextHelper } = useTamboContextHelpers();
48
- // Track which context helpers have been registered to avoid duplicates
49
- const registeredIdsRef = useRef(new Set());
50
- const prevGetContextHelperDataRef = useRef();
51
- // Sync context helpers with attachments using useEffect
24
+ const [attachments, setAttachments] = useState([]);
52
25
  useEffect(() => {
53
- const currentIds = attachments.map((a) => a.id);
54
- const registeredIds = registeredIdsRef.current;
55
- // Remove context helpers that are no longer in attachments
56
- registeredIds.forEach((id) => {
57
- if (!currentIds.includes(id)) {
58
- removeContextHelper(id);
59
- registeredIds.delete(id);
26
+ addContextHelper(CONTEXT_ATTACHMENTS_HELPER_KEY, () => {
27
+ if (attachments.length === 0) {
28
+ return null;
60
29
  }
30
+ return attachments.map((attachment) => ({
31
+ id: attachment.id,
32
+ displayName: attachment.displayName,
33
+ context: attachment.context,
34
+ type: attachment.type,
35
+ }));
61
36
  });
62
- const getDataChanged = prevGetContextHelperDataRef.current !== getContextHelperData;
63
- // Add or replace context helpers for attachments
64
- attachments.forEach((context) => {
65
- if (getDataChanged || !registeredIds.has(context.id)) {
66
- addContextHelper(context.id, async () => {
67
- if (getContextHelperData) {
68
- return await getContextHelperData(context);
69
- }
70
- return {
71
- selectedComponent: {
72
- name: context.name,
73
- instruction: "This is a Tambo interactable component that is currently selected and visible on the dashboard. You can read its current props and state, and update it by modifying its props. If multiple components are attached, you can interact with and modify any of them. Use the auto-registered interactable component tools (like get_interactable_component_by_id and update_interactable_component_<id>) to view and update the component's state.",
74
- ...(context.metadata ?? {}),
75
- },
76
- };
77
- });
78
- registeredIds.add(context.id);
79
- }
80
- });
81
- prevGetContextHelperDataRef.current = getContextHelperData;
82
- }, [
83
- attachments,
84
- addContextHelper,
85
- removeContextHelper,
86
- getContextHelperData,
87
- ]);
88
- // Cleanup: remove all context helpers on unmount
89
- useEffect(() => {
90
- const registeredIds = registeredIdsRef.current;
91
37
  return () => {
92
- registeredIds.forEach((id) => {
93
- removeContextHelper(id);
94
- });
95
- registeredIds.clear();
38
+ removeContextHelper(CONTEXT_ATTACHMENTS_HELPER_KEY);
96
39
  };
97
- }, [removeContextHelper]);
98
- const addContextAttachment = useCallback((context) => {
99
- setAttachments((prev) => {
100
- if (prev.some((c) => c.name === context.name))
101
- return prev;
102
- if (typeof crypto === "undefined" || !("randomUUID" in crypto)) {
103
- throw new Error("crypto.randomUUID() is not available. This usually happens when using an IP address instead of 'localhost' in development. Use 'localhost' or a secure context (HTTPS) to enable crypto APIs.");
104
- }
105
- const newId = crypto.randomUUID();
106
- const newContext = { ...context, id: newId };
107
- return [...prev, newContext];
108
- });
40
+ }, [attachments, addContextHelper, removeContextHelper]);
41
+ /**
42
+ * Adds a new context attachment that will be included with the next user message.
43
+ * The attachment is automatically registered as part of the merged context helper.
44
+ * @param contextAttachment - The context attachment input (context, optional displayName, optional type)
45
+ * @returns The created ContextAttachment object with a unique ID
46
+ * @example
47
+ * ```tsx
48
+ * const attachment = addContextAttachment({
49
+ * context: "The contents of File.txt",
50
+ * displayName: "File.txt",
51
+ * type: "file"
52
+ * });
53
+ * ```
54
+ */
55
+ const addContextAttachment = useCallback((contextAttachment) => {
56
+ const id = crypto.randomUUID();
57
+ const attachment = {
58
+ id,
59
+ displayName: contextAttachment.displayName,
60
+ context: contextAttachment.context,
61
+ type: contextAttachment.type,
62
+ };
63
+ setAttachments((prev) => [...prev, attachment]);
64
+ return attachment;
109
65
  }, []);
110
- // This is used to remove a context when the user clicks the remove button
66
+ /**
67
+ * Removes a context attachment by its ID.
68
+ */
111
69
  const removeContextAttachment = useCallback((id) => {
112
70
  setAttachments((prev) => prev.filter((c) => c.id !== id));
113
71
  }, []);
114
- // This is used to clear the context when the user submits a message
72
+ /**
73
+ * Removes all context attachments at once.
74
+ */
115
75
  const clearContextAttachments = useCallback(() => {
116
76
  setAttachments([]);
117
77
  }, []);
@@ -120,14 +80,11 @@ export function TamboContextAttachmentProvider({ children, getContextHelperData,
120
80
  addContextAttachment,
121
81
  removeContextAttachment,
122
82
  clearContextAttachments,
123
- customSuggestions,
124
- setCustomSuggestions,
125
83
  }), [
126
84
  attachments,
127
85
  addContextAttachment,
128
86
  removeContextAttachment,
129
87
  clearContextAttachments,
130
- customSuggestions,
131
88
  ]);
132
89
  return (React.createElement(ContextAttachmentContext.Provider, { value: value }, children));
133
90
  }
@@ -138,20 +95,20 @@ export function TamboContextAttachmentProvider({ children, getContextHelperData,
138
95
  * @returns The context attachment state and methods
139
96
  * @example
140
97
  * ```tsx
141
- * const contextAttachment = useTamboContextAttachment();
98
+ * const { addContextAttachment, attachments, clearContextAttachments } = useTamboContextAttachment();
142
99
  *
143
- * // Add a context
144
- * contextAttachment.addContextAttachment({
145
- * name: "Button.tsx",
146
- * icon: <FileIcon />,
147
- * metadata: { path: "/src/Button.tsx" }
100
+ * // Add a context attachment for the next message
101
+ * const attachment = addContextAttachment({
102
+ * context: "The contents of File.txt",
103
+ * displayName: "File.txt", // optional
104
+ * type: "file" // optional
148
105
  * });
149
106
  *
150
- * // Remove a context
151
- * contextAttachment.removeContextAttachment(contextId);
107
+ * // Remove a context attachment
108
+ * removeContextAttachment(attachment.id);
152
109
  *
153
- * // Set custom suggestions
154
- * contextAttachment.setCustomSuggestions([{ id: "1", title: "Add Feature" }]);
110
+ * // Clear all context attachments
111
+ * clearContextAttachments();
155
112
  * ```
156
113
  */
157
114
  export function useTamboContextAttachment() {