@tambo-ai/react 0.74.0 → 0.75.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 (314) hide show
  1. package/README.md +46 -449
  2. package/dist/hoc/with-tambo-interactable.d.ts +8 -0
  3. package/dist/hoc/with-tambo-interactable.d.ts.map +1 -1
  4. package/dist/hoc/with-tambo-interactable.js +5 -2
  5. package/dist/hoc/with-tambo-interactable.js.map +1 -1
  6. package/dist/hoc/with-tambo-interactable.test.js +12 -0
  7. package/dist/hoc/with-tambo-interactable.test.js.map +1 -1
  8. package/dist/hooks/use-tambo-voice.test.js +3 -0
  9. package/dist/hooks/use-tambo-voice.test.js.map +1 -1
  10. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  11. package/dist/mcp/mcp-hooks.js +70 -16
  12. package/dist/mcp/mcp-hooks.js.map +1 -1
  13. package/dist/mcp/mcp-hooks.test.js +69 -0
  14. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  15. package/dist/mcp/tambo-mcp-provider.test.js +24 -0
  16. package/dist/mcp/tambo-mcp-provider.test.js.map +1 -1
  17. package/dist/mcp/use-mcp-servers.test.js +9 -0
  18. package/dist/mcp/use-mcp-servers.test.js.map +1 -1
  19. package/dist/model/component-metadata.d.ts +4 -4
  20. package/dist/model/component-metadata.js.map +1 -1
  21. package/dist/providers/__tests__/thread-input-resource-resolution.test.js +2 -2
  22. package/dist/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -1
  23. package/dist/providers/tambo-client-provider.d.ts +6 -0
  24. package/dist/providers/tambo-client-provider.d.ts.map +1 -1
  25. package/dist/providers/tambo-client-provider.js +4 -1
  26. package/dist/providers/tambo-client-provider.js.map +1 -1
  27. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  28. package/dist/providers/tambo-interactable-provider.js +8 -0
  29. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  30. package/dist/providers/tambo-interactable-provider.test.js +47 -0
  31. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  32. package/dist/providers/tambo-provider.d.ts.map +1 -1
  33. package/dist/providers/tambo-provider.js +4 -1
  34. package/dist/providers/tambo-provider.js.map +1 -1
  35. package/dist/providers/tambo-stubs.d.ts.map +1 -1
  36. package/dist/providers/tambo-stubs.js +3 -0
  37. package/dist/providers/tambo-stubs.js.map +1 -1
  38. package/dist/providers/tambo-thread-provider-initial-messages.test.js +3 -0
  39. package/dist/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  40. package/dist/providers/tambo-thread-provider.test.js +3 -0
  41. package/dist/providers/tambo-thread-provider.test.js.map +1 -1
  42. package/dist/util/registry-validators.js +1 -1
  43. package/dist/util/registry-validators.js.map +1 -1
  44. package/dist/util/resource-content-resolver.test.js +1 -1
  45. package/dist/util/resource-content-resolver.test.js.map +1 -1
  46. package/dist/v1/hooks/use-tambo-v1-auth-state.d.ts +11 -0
  47. package/dist/v1/hooks/use-tambo-v1-auth-state.d.ts.map +1 -0
  48. package/dist/v1/hooks/use-tambo-v1-auth-state.js +48 -0
  49. package/dist/v1/hooks/use-tambo-v1-auth-state.js.map +1 -0
  50. package/dist/v1/hooks/use-tambo-v1-auth-state.test.d.ts +2 -0
  51. package/dist/v1/hooks/use-tambo-v1-auth-state.test.d.ts.map +1 -0
  52. package/dist/v1/hooks/use-tambo-v1-auth-state.test.js +105 -0
  53. package/dist/v1/hooks/use-tambo-v1-auth-state.test.js.map +1 -0
  54. package/dist/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
  55. package/dist/v1/hooks/use-tambo-v1-component-state.js +68 -21
  56. package/dist/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  57. package/dist/v1/hooks/use-tambo-v1-component-state.test.js +100 -0
  58. package/dist/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  59. package/dist/v1/hooks/use-tambo-v1-messages.test.js +8 -0
  60. package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  61. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +19 -1
  62. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  63. package/dist/v1/hooks/use-tambo-v1-send-message.js +86 -9
  64. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  65. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +273 -0
  66. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  67. package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts +2 -2
  68. package/dist/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -1
  69. package/dist/v1/hooks/use-tambo-v1-stream-status.js +2 -2
  70. package/dist/v1/hooks/use-tambo-v1-stream-status.js.map +1 -1
  71. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js +11 -11
  72. package/dist/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -1
  73. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js +13 -0
  74. package/dist/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  75. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  76. package/dist/v1/hooks/use-tambo-v1-thread-list.js +4 -0
  77. package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  78. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +6 -0
  79. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  80. package/dist/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
  81. package/dist/v1/hooks/use-tambo-v1-thread.js +4 -0
  82. package/dist/v1/hooks/use-tambo-v1-thread.js.map +1 -1
  83. package/dist/v1/hooks/use-tambo-v1-thread.test.js +6 -0
  84. package/dist/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
  85. package/dist/v1/hooks/use-tambo-v1.d.ts +11 -0
  86. package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  87. package/dist/v1/hooks/use-tambo-v1.js +5 -0
  88. package/dist/v1/hooks/use-tambo-v1.js.map +1 -1
  89. package/dist/v1/hooks/use-tambo-v1.test.js +13 -0
  90. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -1
  91. package/dist/v1/index.d.ts +4 -1
  92. package/dist/v1/index.d.ts.map +1 -1
  93. package/dist/v1/index.js +5 -2
  94. package/dist/v1/index.js.map +1 -1
  95. package/dist/v1/providers/tambo-v1-provider.d.ts +16 -1
  96. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  97. package/dist/v1/providers/tambo-v1-provider.js +42 -5
  98. package/dist/v1/providers/tambo-v1-provider.js.map +1 -1
  99. package/dist/v1/providers/tambo-v1-provider.test.js +19 -2
  100. package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -1
  101. package/dist/v1/providers/tambo-v1-stream-context.d.ts +6 -0
  102. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  103. package/dist/v1/providers/tambo-v1-stream-context.js +50 -11
  104. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -1
  105. package/dist/v1/providers/tambo-v1-stream-context.test.js +9 -0
  106. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  107. package/dist/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  108. package/dist/v1/providers/tambo-v1-stub-provider.js +4 -0
  109. package/dist/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  110. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts +11 -0
  111. package/dist/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  112. package/dist/v1/providers/tambo-v1-thread-input-provider.js +10 -1
  113. package/dist/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  114. package/dist/v1/types/auth.d.ts +24 -0
  115. package/dist/v1/types/auth.d.ts.map +1 -0
  116. package/dist/v1/types/auth.js +3 -0
  117. package/dist/v1/types/auth.js.map +1 -0
  118. package/dist/v1/types/message.d.ts +12 -0
  119. package/dist/v1/types/message.d.ts.map +1 -1
  120. package/dist/v1/types/message.js.map +1 -1
  121. package/dist/v1/types/tool-choice.d.ts +8 -0
  122. package/dist/v1/types/tool-choice.d.ts.map +1 -0
  123. package/dist/v1/types/tool-choice.js +3 -0
  124. package/dist/v1/types/tool-choice.js.map +1 -0
  125. package/dist/v1/utils/event-accumulator.d.ts +28 -2
  126. package/dist/v1/utils/event-accumulator.d.ts.map +1 -1
  127. package/dist/v1/utils/event-accumulator.js +67 -15
  128. package/dist/v1/utils/event-accumulator.js.map +1 -1
  129. package/dist/v1/utils/event-accumulator.test.js +106 -0
  130. package/dist/v1/utils/event-accumulator.test.js.map +1 -1
  131. package/dist/v1/utils/keyed-throttle.d.ts +42 -0
  132. package/dist/v1/utils/keyed-throttle.d.ts.map +1 -0
  133. package/dist/v1/utils/keyed-throttle.js +86 -0
  134. package/dist/v1/utils/keyed-throttle.js.map +1 -0
  135. package/dist/v1/utils/keyed-throttle.test.d.ts +2 -0
  136. package/dist/v1/utils/keyed-throttle.test.d.ts.map +1 -0
  137. package/dist/v1/utils/keyed-throttle.test.js +147 -0
  138. package/dist/v1/utils/keyed-throttle.test.js.map +1 -0
  139. package/dist/v1/utils/registry-conversion.d.ts.map +1 -1
  140. package/dist/v1/utils/registry-conversion.js +2 -0
  141. package/dist/v1/utils/registry-conversion.js.map +1 -1
  142. package/dist/v1/utils/registry-conversion.test.js +23 -0
  143. package/dist/v1/utils/registry-conversion.test.js.map +1 -1
  144. package/dist/v1/utils/tool-call-tracker.d.ts +10 -0
  145. package/dist/v1/utils/tool-call-tracker.d.ts.map +1 -1
  146. package/dist/v1/utils/tool-call-tracker.js +13 -0
  147. package/dist/v1/utils/tool-call-tracker.js.map +1 -1
  148. package/dist/v1/utils/tool-call-tracker.test.d.ts +2 -0
  149. package/dist/v1/utils/tool-call-tracker.test.d.ts.map +1 -0
  150. package/dist/v1/utils/tool-call-tracker.test.js +67 -0
  151. package/dist/v1/utils/tool-call-tracker.test.js.map +1 -0
  152. package/dist/v1/utils/tool-executor.d.ts +34 -0
  153. package/dist/v1/utils/tool-executor.d.ts.map +1 -1
  154. package/dist/v1/utils/tool-executor.js +55 -0
  155. package/dist/v1/utils/tool-executor.js.map +1 -1
  156. package/dist/v1/utils/tool-executor.test.js +211 -0
  157. package/dist/v1/utils/tool-executor.test.js.map +1 -1
  158. package/esm/hoc/with-tambo-interactable.d.ts +8 -0
  159. package/esm/hoc/with-tambo-interactable.d.ts.map +1 -1
  160. package/esm/hoc/with-tambo-interactable.js +5 -2
  161. package/esm/hoc/with-tambo-interactable.js.map +1 -1
  162. package/esm/hoc/with-tambo-interactable.test.js +12 -0
  163. package/esm/hoc/with-tambo-interactable.test.js.map +1 -1
  164. package/esm/hooks/use-tambo-voice.test.js +3 -0
  165. package/esm/hooks/use-tambo-voice.test.js.map +1 -1
  166. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  167. package/esm/mcp/mcp-hooks.js +70 -16
  168. package/esm/mcp/mcp-hooks.js.map +1 -1
  169. package/esm/mcp/mcp-hooks.test.js +69 -0
  170. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  171. package/esm/mcp/tambo-mcp-provider.test.js +24 -0
  172. package/esm/mcp/tambo-mcp-provider.test.js.map +1 -1
  173. package/esm/mcp/use-mcp-servers.test.js +9 -0
  174. package/esm/mcp/use-mcp-servers.test.js.map +1 -1
  175. package/esm/model/component-metadata.d.ts +4 -4
  176. package/esm/model/component-metadata.js.map +1 -1
  177. package/esm/providers/__tests__/thread-input-resource-resolution.test.js +2 -2
  178. package/esm/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -1
  179. package/esm/providers/tambo-client-provider.d.ts +6 -0
  180. package/esm/providers/tambo-client-provider.d.ts.map +1 -1
  181. package/esm/providers/tambo-client-provider.js +4 -1
  182. package/esm/providers/tambo-client-provider.js.map +1 -1
  183. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  184. package/esm/providers/tambo-interactable-provider.js +8 -0
  185. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  186. package/esm/providers/tambo-interactable-provider.test.js +47 -0
  187. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  188. package/esm/providers/tambo-provider.d.ts.map +1 -1
  189. package/esm/providers/tambo-provider.js +4 -1
  190. package/esm/providers/tambo-provider.js.map +1 -1
  191. package/esm/providers/tambo-stubs.d.ts.map +1 -1
  192. package/esm/providers/tambo-stubs.js +3 -0
  193. package/esm/providers/tambo-stubs.js.map +1 -1
  194. package/esm/providers/tambo-thread-provider-initial-messages.test.js +3 -0
  195. package/esm/providers/tambo-thread-provider-initial-messages.test.js.map +1 -1
  196. package/esm/providers/tambo-thread-provider.test.js +3 -0
  197. package/esm/providers/tambo-thread-provider.test.js.map +1 -1
  198. package/esm/util/registry-validators.js +1 -1
  199. package/esm/util/registry-validators.js.map +1 -1
  200. package/esm/util/resource-content-resolver.test.js +1 -1
  201. package/esm/util/resource-content-resolver.test.js.map +1 -1
  202. package/esm/v1/hooks/use-tambo-v1-auth-state.d.ts +11 -0
  203. package/esm/v1/hooks/use-tambo-v1-auth-state.d.ts.map +1 -0
  204. package/esm/v1/hooks/use-tambo-v1-auth-state.js +45 -0
  205. package/esm/v1/hooks/use-tambo-v1-auth-state.js.map +1 -0
  206. package/esm/v1/hooks/use-tambo-v1-auth-state.test.d.ts +2 -0
  207. package/esm/v1/hooks/use-tambo-v1-auth-state.test.d.ts.map +1 -0
  208. package/esm/v1/hooks/use-tambo-v1-auth-state.test.js +100 -0
  209. package/esm/v1/hooks/use-tambo-v1-auth-state.test.js.map +1 -0
  210. package/esm/v1/hooks/use-tambo-v1-component-state.d.ts.map +1 -1
  211. package/esm/v1/hooks/use-tambo-v1-component-state.js +68 -21
  212. package/esm/v1/hooks/use-tambo-v1-component-state.js.map +1 -1
  213. package/esm/v1/hooks/use-tambo-v1-component-state.test.js +100 -0
  214. package/esm/v1/hooks/use-tambo-v1-component-state.test.js.map +1 -1
  215. package/esm/v1/hooks/use-tambo-v1-messages.test.js +8 -0
  216. package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -1
  217. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +19 -1
  218. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -1
  219. package/esm/v1/hooks/use-tambo-v1-send-message.js +87 -10
  220. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -1
  221. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +273 -0
  222. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -1
  223. package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts +2 -2
  224. package/esm/v1/hooks/use-tambo-v1-stream-status.d.ts.map +1 -1
  225. package/esm/v1/hooks/use-tambo-v1-stream-status.js +2 -2
  226. package/esm/v1/hooks/use-tambo-v1-stream-status.js.map +1 -1
  227. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js +11 -11
  228. package/esm/v1/hooks/use-tambo-v1-stream-status.test.js.map +1 -1
  229. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js +13 -0
  230. package/esm/v1/hooks/use-tambo-v1-thread-input.test.js.map +1 -1
  231. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -1
  232. package/esm/v1/hooks/use-tambo-v1-thread-list.js +4 -0
  233. package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -1
  234. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +6 -0
  235. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -1
  236. package/esm/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -1
  237. package/esm/v1/hooks/use-tambo-v1-thread.js +4 -0
  238. package/esm/v1/hooks/use-tambo-v1-thread.js.map +1 -1
  239. package/esm/v1/hooks/use-tambo-v1-thread.test.js +6 -0
  240. package/esm/v1/hooks/use-tambo-v1-thread.test.js.map +1 -1
  241. package/esm/v1/hooks/use-tambo-v1.d.ts +11 -0
  242. package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -1
  243. package/esm/v1/hooks/use-tambo-v1.js +5 -0
  244. package/esm/v1/hooks/use-tambo-v1.js.map +1 -1
  245. package/esm/v1/hooks/use-tambo-v1.test.js +13 -0
  246. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -1
  247. package/esm/v1/index.d.ts +4 -1
  248. package/esm/v1/index.d.ts.map +1 -1
  249. package/esm/v1/index.js +3 -1
  250. package/esm/v1/index.js.map +1 -1
  251. package/esm/v1/providers/tambo-v1-provider.d.ts +16 -1
  252. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -1
  253. package/esm/v1/providers/tambo-v1-provider.js +43 -6
  254. package/esm/v1/providers/tambo-v1-provider.js.map +1 -1
  255. package/esm/v1/providers/tambo-v1-provider.test.js +19 -2
  256. package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -1
  257. package/esm/v1/providers/tambo-v1-stream-context.d.ts +6 -0
  258. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -1
  259. package/esm/v1/providers/tambo-v1-stream-context.js +51 -12
  260. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -1
  261. package/esm/v1/providers/tambo-v1-stream-context.test.js +9 -0
  262. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -1
  263. package/esm/v1/providers/tambo-v1-stub-provider.d.ts.map +1 -1
  264. package/esm/v1/providers/tambo-v1-stub-provider.js +4 -0
  265. package/esm/v1/providers/tambo-v1-stub-provider.js.map +1 -1
  266. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts +11 -0
  267. package/esm/v1/providers/tambo-v1-thread-input-provider.d.ts.map +1 -1
  268. package/esm/v1/providers/tambo-v1-thread-input-provider.js +10 -1
  269. package/esm/v1/providers/tambo-v1-thread-input-provider.js.map +1 -1
  270. package/esm/v1/types/auth.d.ts +24 -0
  271. package/esm/v1/types/auth.d.ts.map +1 -0
  272. package/esm/v1/types/auth.js +2 -0
  273. package/esm/v1/types/auth.js.map +1 -0
  274. package/esm/v1/types/message.d.ts +12 -0
  275. package/esm/v1/types/message.d.ts.map +1 -1
  276. package/esm/v1/types/message.js.map +1 -1
  277. package/esm/v1/types/tool-choice.d.ts +8 -0
  278. package/esm/v1/types/tool-choice.d.ts.map +1 -0
  279. package/esm/v1/types/tool-choice.js +2 -0
  280. package/esm/v1/types/tool-choice.js.map +1 -0
  281. package/esm/v1/utils/event-accumulator.d.ts +28 -2
  282. package/esm/v1/utils/event-accumulator.d.ts.map +1 -1
  283. package/esm/v1/utils/event-accumulator.js +66 -15
  284. package/esm/v1/utils/event-accumulator.js.map +1 -1
  285. package/esm/v1/utils/event-accumulator.test.js +106 -0
  286. package/esm/v1/utils/event-accumulator.test.js.map +1 -1
  287. package/esm/v1/utils/keyed-throttle.d.ts +42 -0
  288. package/esm/v1/utils/keyed-throttle.d.ts.map +1 -0
  289. package/esm/v1/utils/keyed-throttle.js +83 -0
  290. package/esm/v1/utils/keyed-throttle.js.map +1 -0
  291. package/esm/v1/utils/keyed-throttle.test.d.ts +2 -0
  292. package/esm/v1/utils/keyed-throttle.test.d.ts.map +1 -0
  293. package/esm/v1/utils/keyed-throttle.test.js +145 -0
  294. package/esm/v1/utils/keyed-throttle.test.js.map +1 -0
  295. package/esm/v1/utils/registry-conversion.d.ts.map +1 -1
  296. package/esm/v1/utils/registry-conversion.js +2 -0
  297. package/esm/v1/utils/registry-conversion.js.map +1 -1
  298. package/esm/v1/utils/registry-conversion.test.js +23 -0
  299. package/esm/v1/utils/registry-conversion.test.js.map +1 -1
  300. package/esm/v1/utils/tool-call-tracker.d.ts +10 -0
  301. package/esm/v1/utils/tool-call-tracker.d.ts.map +1 -1
  302. package/esm/v1/utils/tool-call-tracker.js +13 -0
  303. package/esm/v1/utils/tool-call-tracker.js.map +1 -1
  304. package/esm/v1/utils/tool-call-tracker.test.d.ts +2 -0
  305. package/esm/v1/utils/tool-call-tracker.test.d.ts.map +1 -0
  306. package/esm/v1/utils/tool-call-tracker.test.js +65 -0
  307. package/esm/v1/utils/tool-call-tracker.test.js.map +1 -0
  308. package/esm/v1/utils/tool-executor.d.ts +34 -0
  309. package/esm/v1/utils/tool-executor.d.ts.map +1 -1
  310. package/esm/v1/utils/tool-executor.js +53 -0
  311. package/esm/v1/utils/tool-executor.js.map +1 -1
  312. package/esm/v1/utils/tool-executor.test.js +212 -1
  313. package/esm/v1/utils/tool-executor.test.js.map +1 -1
  314. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"with-tambo-interactable.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { TamboMessageProvider } from \"../hooks/use-current-message\";\nimport { TamboThreadMessage } from \"../model/generate-component-response\";\nimport { useTamboInteractable } from \"../providers/tambo-interactable-provider\";\nimport { SupportedSchema } from \"../schema\";\n\nexport interface InteractableConfig<\n Props = Record<string, unknown>,\n State = Record<string, unknown>,\n> {\n /**\n * The name of the component, used for identification in Tambo.\n */\n componentName: string;\n /**\n * A brief description of the component's purpose and functionality. LLM will\n * use this to understand how to interact with it.\n */\n description: string;\n /**\n * Optional schema for component props. If provided, prop updates will be\n * validated against this schema.\n */\n propsSchema?: SupportedSchema<Props>;\n /**\n * Optional schema for component state. If provided, state updates will be\n * validated against this schema.\n */\n stateSchema?: SupportedSchema<State>;\n}\n\n/**\n * Props injected by withTamboInteractable HOC. These can be passed to the wrapped\n * component to customize interactable behavior.\n */\nexport interface WithTamboInteractableProps {\n /**\n * Optional ID to use for this interactable component instance.\n * If not provided, a unique ID will be generated automatically.\n */\n interactableId?: string;\n /**\n * Callback fired when the component has been registered as interactable.\n * @param id - The assigned interactable component ID\n */\n onInteractableReady?: (id: string) => void;\n /**\n * Callback fired when the component's serializable props are updated by Tambo\n * through a tool call. Note: Only serializable props are tracked.\n * @param newProps - The updated serializable props\n */\n onPropsUpdate?: (newProps: Record<string, unknown>) => void;\n}\n\n/**\n * Higher-Order Component that makes any component interactable by tambo.\n * @param WrappedComponent - The component to make interactable\n * @param config - Configuration for the interactable component\n * @returns A new component that is automatically registered as interactable\n * @example\n * ```tsx\n * const MyNote: React.FC<{ title: string; content: string }> = ({ title, content }) => {\n * const [isPinned, setIsPinned] = useTamboComponentState(\"isPinned\", false);\n * return (\n * <div style={{ border: isPinned ? \"2px solid gold\" : \"1px solid gray\", order: isPinned ? -1 : 0 }}>\n * <h2>{title}</h2>\n * <p>{content}</p>\n * </div>\n * );\n * };\n *\n * const MyInteractableNote = withTamboInteractable(MyNote, {\n * componentName: \"MyNote\",\n * description: \"A note component\",\n * propsSchema: z.object({\n * title: z.string(),\n * content: z.string(),\n * }),\n * stateSchema: z.object({\n * isPinned: z.boolean(),\n * }),\n * });\n *\n * // Usage\n * <MyInteractableNote title=\"My Note\" content=\"This is my note\" />\n * ```\n */\nexport function withTamboInteractable<ComponentProps extends object>(\n WrappedComponent: React.ComponentType<ComponentProps>,\n config: InteractableConfig,\n) {\n const displayName =\n WrappedComponent.displayName ?? WrappedComponent.name ?? \"Component\";\n\n const TamboInteractableWrapper: React.FC<\n ComponentProps & WithTamboInteractableProps\n > = (props) => {\n const {\n addInteractableComponent,\n updateInteractableComponentProps,\n getInteractableComponent,\n } = useTamboInteractable();\n\n const [interactableId, setInteractableId] = useState<string | null>(null);\n const isInitialized = useRef(false);\n const lastSerializedProps = useRef<Record<string, unknown>>({});\n\n // Extract interactable-specific props from component props\n const {\n interactableId: _providedId, // Reserved for future use\n onInteractableReady,\n onPropsUpdate,\n ...componentProps\n } = props;\n\n // Get the current interactable component to track prop updates\n const currentInteractable = interactableId\n ? getInteractableComponent(interactableId)\n : null;\n\n // Use the props from the interactable component if available, otherwise use the passed props\n // We need to be careful not to create a loop, so we only use stored props if they're different from passed props\n const effectiveProps = currentInteractable?.props ?? componentProps;\n\n // Memoize the registration function\n const registerComponent = useCallback(() => {\n if (!isInitialized.current) {\n const id = addInteractableComponent({\n name: config.componentName,\n description: config.description,\n component: WrappedComponent,\n props: componentProps,\n propsSchema: config.propsSchema,\n stateSchema: config.stateSchema,\n });\n\n setInteractableId(id);\n onInteractableReady?.(id);\n isInitialized.current = true;\n }\n }, [addInteractableComponent, componentProps, onInteractableReady]);\n\n // Register the component as interactable on mount (only once)\n useEffect(() => {\n registerComponent();\n }, [registerComponent]);\n\n // Update the interactable component when props change from parent\n useEffect(() => {\n if (interactableId && isInitialized.current) {\n // Only update if the props are different from what we last sent\n const lastPropsString = JSON.stringify(lastSerializedProps.current);\n const currentPropsString = JSON.stringify(componentProps);\n\n if (lastPropsString !== currentPropsString) {\n updateInteractableComponentProps(interactableId, componentProps);\n onPropsUpdate?.(componentProps);\n lastSerializedProps.current = componentProps;\n }\n }\n }, [\n interactableId,\n componentProps,\n updateInteractableComponentProps,\n onPropsUpdate,\n ]);\n\n // If the interactable ID is not yet set, render the component without provider\n if (!interactableId) {\n return <WrappedComponent {...(effectiveProps as ComponentProps)} />;\n }\n\n // Create a minimal message with interactable metadata\n // This allows useTamboCurrentComponent to work with standalone interactable components\n const minimalMessage: TamboThreadMessage = {\n id: interactableId,\n role: \"assistant\" as const,\n content: [],\n threadId: \"\",\n createdAt: new Date().toISOString(),\n component: {\n componentName: config.componentName,\n componentState: {},\n message: \"\",\n props: effectiveProps,\n },\n componentState: {},\n };\n\n // Wrap with TamboMessageProvider including interactable metadata\n return (\n <TamboMessageProvider\n message={minimalMessage}\n interactableMetadata={{\n id: interactableId,\n componentName: config.componentName,\n description: config.description,\n }}\n >\n <WrappedComponent {...(effectiveProps as ComponentProps)} />\n </TamboMessageProvider>\n );\n };\n\n TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;\n\n return TamboInteractableWrapper;\n}\n"]}
1
+ {"version":3,"file":"with-tambo-interactable.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { TamboMessageProvider } from \"../hooks/use-current-message\";\nimport type { ToolAnnotations } from \"../model/component-metadata\";\nimport { TamboThreadMessage } from \"../model/generate-component-response\";\nimport { useTamboInteractable } from \"../providers/tambo-interactable-provider\";\nimport { SupportedSchema } from \"../schema\";\nimport { V1ComponentContentProvider } from \"../v1/utils/component-renderer\";\n\nexport interface InteractableConfig<\n Props = Record<string, unknown>,\n State = Record<string, unknown>,\n> {\n /**\n * The name of the component, used for identification in Tambo.\n */\n componentName: string;\n /**\n * A brief description of the component's purpose and functionality. LLM will\n * use this to understand how to interact with it.\n */\n description: string;\n /**\n * Optional schema for component props. If provided, prop updates will be\n * validated against this schema.\n */\n propsSchema?: SupportedSchema<Props>;\n /**\n * Optional schema for component state. If provided, state updates will be\n * validated against this schema.\n */\n stateSchema?: SupportedSchema<State>;\n /**\n * Optional annotations for the interactable component's auto-registered tools\n * (props update and state update). By default, `tamboStreamableHint` is `true`\n * so props/state updates stream in real-time. Set `{ tamboStreamableHint: false }`\n * to disable streaming for this component's tools.\n */\n annotations?: ToolAnnotations;\n}\n\n/**\n * Props injected by withTamboInteractable HOC. These can be passed to the wrapped\n * component to customize interactable behavior.\n */\nexport interface WithTamboInteractableProps {\n /**\n * Optional ID to use for this interactable component instance.\n * If not provided, a unique ID will be generated automatically.\n */\n interactableId?: string;\n /**\n * Callback fired when the component has been registered as interactable.\n * @param id - The assigned interactable component ID\n */\n onInteractableReady?: (id: string) => void;\n /**\n * Callback fired when the component's serializable props are updated by Tambo\n * through a tool call. Note: Only serializable props are tracked.\n * @param newProps - The updated serializable props\n */\n onPropsUpdate?: (newProps: Record<string, unknown>) => void;\n}\n\n/**\n * Higher-Order Component that makes any component interactable by tambo.\n * @param WrappedComponent - The component to make interactable\n * @param config - Configuration for the interactable component\n * @returns A new component that is automatically registered as interactable\n * @example\n * ```tsx\n * const MyNote: React.FC<{ title: string; content: string }> = ({ title, content }) => {\n * const [isPinned, setIsPinned] = useTamboComponentState(\"isPinned\", false);\n * return (\n * <div style={{ border: isPinned ? \"2px solid gold\" : \"1px solid gray\", order: isPinned ? -1 : 0 }}>\n * <h2>{title}</h2>\n * <p>{content}</p>\n * </div>\n * );\n * };\n *\n * const MyInteractableNote = withTamboInteractable(MyNote, {\n * componentName: \"MyNote\",\n * description: \"A note component\",\n * propsSchema: z.object({\n * title: z.string(),\n * content: z.string(),\n * }),\n * stateSchema: z.object({\n * isPinned: z.boolean(),\n * }),\n * });\n *\n * // Usage\n * <MyInteractableNote title=\"My Note\" content=\"This is my note\" />\n * ```\n */\nexport function withTamboInteractable<ComponentProps extends object>(\n WrappedComponent: React.ComponentType<ComponentProps>,\n config: InteractableConfig,\n) {\n const displayName =\n WrappedComponent.displayName ?? WrappedComponent.name ?? \"Component\";\n\n const TamboInteractableWrapper: React.FC<\n ComponentProps & WithTamboInteractableProps\n > = (props) => {\n const {\n addInteractableComponent,\n updateInteractableComponentProps,\n getInteractableComponent,\n } = useTamboInteractable();\n\n const [interactableId, setInteractableId] = useState<string | null>(null);\n const isInitialized = useRef(false);\n const lastSerializedProps = useRef<Record<string, unknown>>({});\n\n // Extract interactable-specific props from component props\n const {\n interactableId: _providedId, // Reserved for future use\n onInteractableReady,\n onPropsUpdate,\n ...componentProps\n } = props;\n\n // Get the current interactable component to track prop updates\n const currentInteractable = interactableId\n ? getInteractableComponent(interactableId)\n : null;\n\n // Use the props from the interactable component if available, otherwise use the passed props\n // We need to be careful not to create a loop, so we only use stored props if they're different from passed props\n const effectiveProps = currentInteractable?.props ?? componentProps;\n\n // Memoize the registration function\n const registerComponent = useCallback(() => {\n if (!isInitialized.current) {\n const id = addInteractableComponent({\n name: config.componentName,\n description: config.description,\n component: WrappedComponent,\n props: componentProps,\n propsSchema: config.propsSchema,\n stateSchema: config.stateSchema,\n annotations: config.annotations,\n });\n\n setInteractableId(id);\n onInteractableReady?.(id);\n isInitialized.current = true;\n }\n }, [addInteractableComponent, componentProps, onInteractableReady]);\n\n // Register the component as interactable on mount (only once)\n useEffect(() => {\n registerComponent();\n }, [registerComponent]);\n\n // Update the interactable component when props change from parent\n useEffect(() => {\n if (interactableId && isInitialized.current) {\n // Only update if the props are different from what we last sent\n const lastPropsString = JSON.stringify(lastSerializedProps.current);\n const currentPropsString = JSON.stringify(componentProps);\n\n if (lastPropsString !== currentPropsString) {\n updateInteractableComponentProps(interactableId, componentProps);\n onPropsUpdate?.(componentProps);\n lastSerializedProps.current = componentProps;\n }\n }\n }, [\n interactableId,\n componentProps,\n updateInteractableComponentProps,\n onPropsUpdate,\n ]);\n\n // If the interactable ID is not yet set, render the component without provider\n if (!interactableId) {\n return <WrappedComponent {...(effectiveProps as ComponentProps)} />;\n }\n\n // Create a minimal message with interactable metadata\n // This allows useTamboCurrentComponent to work with standalone interactable components\n const minimalMessage: TamboThreadMessage = {\n id: interactableId,\n role: \"assistant\" as const,\n content: [],\n threadId: \"\",\n createdAt: new Date().toISOString(),\n component: {\n componentName: config.componentName,\n componentState: {},\n message: \"\",\n props: effectiveProps,\n },\n componentState: {},\n };\n\n // Wrap with TamboMessageProvider and V1ComponentContentProvider including interactable metadata\n return (\n <TamboMessageProvider\n message={minimalMessage}\n interactableMetadata={{\n id: interactableId,\n componentName: config.componentName,\n description: config.description,\n }}\n >\n <V1ComponentContentProvider\n componentId={interactableId}\n threadId=\"\"\n messageId=\"\"\n componentName={config.componentName}\n >\n <WrappedComponent {...(effectiveProps as ComponentProps)} />\n </V1ComponentContentProvider>\n </TamboMessageProvider>\n );\n };\n\n TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;\n\n return TamboInteractableWrapper;\n}\n"]}
@@ -154,6 +154,18 @@ describe("withTamboInteractable", () => {
154
154
  expect(react_1.screen.getByTestId("has-ready")).toHaveTextContent("no");
155
155
  expect(react_1.screen.getByTestId("has-update")).toHaveTextContent("no");
156
156
  });
157
+ it("should pass annotations config to addInteractableComponent", () => {
158
+ const InteractableComponent = (0, with_tambo_interactable_1.withTamboInteractable)(TestComponent, {
159
+ componentName: "TestComponent",
160
+ description: "A test component",
161
+ annotations: { tamboStreamableHint: false },
162
+ });
163
+ (0, react_1.render)(react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null,
164
+ react_2.default.createElement(InteractableComponent, { title: "Test" })));
165
+ expect(mockAddInteractableComponent).toHaveBeenCalledWith(expect.objectContaining({
166
+ annotations: { tamboStreamableHint: false },
167
+ }));
168
+ });
157
169
  it("should work without propsSchema", () => {
158
170
  const InteractableComponent = (0, with_tambo_interactable_1.withTamboInteractable)(TestComponent, {
159
171
  componentName: "TestComponent",
@@ -1 +1 @@
1
- {"version":3,"file":"with-tambo-interactable.test.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { render, screen, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { z } from \"zod/v3\";\nimport { useTamboCurrentComponent } from \"../hooks/use-current-message\";\nimport { TamboInteractableProvider } from \"../providers/tambo-interactable-provider\";\nimport { withTamboInteractable } from \"./with-tambo-interactable\";\n\n// Create a consistent mock implementation\nconst mockAddInteractableComponent = jest.fn(() => \"mock-id-123\");\nconst mockUpdateInteractableComponentProps = jest.fn();\nconst mockGetInteractableComponent = jest.fn(() => null);\nconst mockRemoveInteractableComponent = jest.fn();\nconst mockGetInteractableComponentsByName = jest.fn(() => []);\nconst mockClearAllInteractableComponents = jest.fn();\n\n// Mock the interactable provider\njest.mock(\"../providers/tambo-interactable-provider\", () => ({\n TamboInteractableProvider: ({ children }: { children: React.ReactNode }) => (\n <div data-testid=\"interactable-provider\">{children}</div>\n ),\n useTamboInteractable: () => ({\n addInteractableComponent: mockAddInteractableComponent,\n updateInteractableComponentProps: mockUpdateInteractableComponentProps,\n getInteractableComponent: mockGetInteractableComponent,\n removeInteractableComponent: mockRemoveInteractableComponent,\n getInteractableComponentsByName: mockGetInteractableComponentsByName,\n clearAllInteractableComponents: mockClearAllInteractableComponents,\n interactableComponents: [],\n }),\n}));\n\ndescribe(\"withTamboInteractable\", () => {\n // Simple test component\n interface TestComponentProps {\n title: string;\n count?: number;\n }\n\n const TestComponent: React.FC<TestComponentProps> = ({ title, count }) => (\n <div>\n <h1 data-testid=\"title\">{title}</h1>\n {count !== undefined && <span data-testid=\"count\">{count}</span>}\n </div>\n );\n\n const testSchema = z.object({\n title: z.string(),\n count: z.number().optional(),\n });\n\n beforeEach(() => {\n jest.clearAllMocks();\n // Reset mock implementations\n mockAddInteractableComponent.mockReturnValue(\"mock-id-123\");\n mockGetInteractableComponent.mockReturnValue(null);\n mockGetInteractableComponentsByName.mockReturnValue([]);\n });\n\n it(\"should render the wrapped component with provided props\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Hello\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"42\");\n });\n\n it(\"should set displayName correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(TestComponent)\",\n );\n });\n\n it(\"should handle components without displayName\", () => {\n const AnonymousComponent = () => <div>Anonymous</div>;\n\n const InteractableComponent = withTamboInteractable(AnonymousComponent, {\n componentName: \"AnonymousComponent\",\n description: \"An anonymous component\",\n });\n\n // Anonymous components get their name from the function name\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(AnonymousComponent)\",\n );\n });\n\n it(\"should provide TamboMessageProvider with interactable metadata\", async () => {\n // Child component that uses the context\n const ContextConsumer = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"interactable-id\">{component?.interactableId}</span>\n <span data-testid=\"component-name\">{component?.componentName}</span>\n <span data-testid=\"description\">{component?.description}</span>\n </div>\n );\n };\n\n // Wrap TestComponent to include ContextConsumer\n const TestComponentWithConsumer: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <ContextConsumer />\n </div>\n );\n\n const InteractableWithConsumer = withTamboInteractable(\n TestComponentWithConsumer,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithConsumer title=\"Hello\" />\n </TamboInteractableProvider>,\n );\n\n // Wait for the component to register and render\n await waitFor(() => {\n expect(screen.getByTestId(\"interactable-id\")).toHaveTextContent(\n \"mock-id-123\",\n );\n });\n\n expect(screen.getByTestId(\"component-name\")).toHaveTextContent(\n \"TestComponent\",\n );\n expect(screen.getByTestId(\"description\")).toHaveTextContent(\n \"A test component\",\n );\n });\n\n it(\"should create minimal message with correct structure\", async () => {\n // Child component that checks the message structure\n const MessageChecker = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"has-component-name\">\n {component?.componentName ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-props\">{component?.props ? \"yes\" : \"no\"}</span>\n <span data-testid=\"has-interactable-id\">\n {component?.interactableId ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-description\">\n {component?.description ? \"yes\" : \"no\"}\n </span>\n </div>\n );\n };\n\n const TestComponentWithChecker: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <MessageChecker />\n </div>\n );\n\n const InteractableWithChecker = withTamboInteractable(\n TestComponentWithChecker,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithChecker title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n await waitFor(() => {\n expect(screen.getByTestId(\"has-component-name\")).toHaveTextContent(\"yes\");\n });\n\n expect(screen.getByTestId(\"has-props\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-interactable-id\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-description\")).toHaveTextContent(\"yes\");\n });\n\n it(\"should pass through all component props correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test Title\" count={100} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test Title\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"100\");\n });\n\n it(\"should filter out interactable-specific props from component props\", () => {\n interface ExtendedProps extends TestComponentProps {\n onInteractableReady?: (id: string) => void;\n onPropsUpdate?: (props: Record<string, any>) => void;\n }\n\n const ExtendedComponent: React.FC<ExtendedProps> = ({\n title,\n onInteractableReady,\n onPropsUpdate,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"has-ready\">\n {onInteractableReady ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-update\">{onPropsUpdate ? \"yes\" : \"no\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(ExtendedComponent, {\n componentName: \"ExtendedComponent\",\n description: \"An extended component\",\n });\n\n const mockReady = jest.fn();\n const mockUpdate = jest.fn();\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent\n title=\"Test\"\n onInteractableReady={mockReady}\n onPropsUpdate={mockUpdate}\n />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n // These props should be filtered out\n expect(screen.getByTestId(\"has-ready\")).toHaveTextContent(\"no\");\n expect(screen.getByTestId(\"has-update\")).toHaveTextContent(\"no\");\n });\n\n it(\"should work without propsSchema\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"No Schema\" />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"No Schema\");\n });\n\n it(\"should render before interactable ID is set\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n const { container } = render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Early Render\" />\n </TamboInteractableProvider>,\n );\n\n // Component should render even before ID is available\n expect(\n container.querySelector('[data-testid=\"title\"]'),\n ).toBeInTheDocument();\n });\n\n it(\"should handle null/undefined values in props\", () => {\n interface NullableProps {\n title: string;\n optional?: string;\n nullable: string | null;\n }\n\n const NullableComponent: React.FC<NullableProps> = ({\n title,\n optional,\n nullable,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"optional\">{optional ?? \"undefined\"}</span>\n <span data-testid=\"nullable\">{nullable ?? \"null\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(NullableComponent, {\n componentName: \"NullableComponent\",\n description: \"A component with nullable props\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test\" nullable={null} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n expect(screen.getByTestId(\"optional\")).toHaveTextContent(\"undefined\");\n expect(screen.getByTestId(\"nullable\")).toHaveTextContent(\"null\");\n });\n});\n"]}
1
+ {"version":3,"file":"with-tambo-interactable.test.js","sourceRoot":"","sources":["../../src/hoc/with-tambo-interactable.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { render, screen, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { z } from \"zod/v3\";\nimport { useTamboCurrentComponent } from \"../hooks/use-current-message\";\nimport { TamboInteractableProvider } from \"../providers/tambo-interactable-provider\";\nimport { withTamboInteractable } from \"./with-tambo-interactable\";\n\n// Create a consistent mock implementation\nconst mockAddInteractableComponent = jest.fn(() => \"mock-id-123\");\nconst mockUpdateInteractableComponentProps = jest.fn();\nconst mockGetInteractableComponent = jest.fn(() => null);\nconst mockRemoveInteractableComponent = jest.fn();\nconst mockGetInteractableComponentsByName = jest.fn(() => []);\nconst mockClearAllInteractableComponents = jest.fn();\n\n// Mock the interactable provider\njest.mock(\"../providers/tambo-interactable-provider\", () => ({\n TamboInteractableProvider: ({ children }: { children: React.ReactNode }) => (\n <div data-testid=\"interactable-provider\">{children}</div>\n ),\n useTamboInteractable: () => ({\n addInteractableComponent: mockAddInteractableComponent,\n updateInteractableComponentProps: mockUpdateInteractableComponentProps,\n getInteractableComponent: mockGetInteractableComponent,\n removeInteractableComponent: mockRemoveInteractableComponent,\n getInteractableComponentsByName: mockGetInteractableComponentsByName,\n clearAllInteractableComponents: mockClearAllInteractableComponents,\n interactableComponents: [],\n }),\n}));\n\ndescribe(\"withTamboInteractable\", () => {\n // Simple test component\n interface TestComponentProps {\n title: string;\n count?: number;\n }\n\n const TestComponent: React.FC<TestComponentProps> = ({ title, count }) => (\n <div>\n <h1 data-testid=\"title\">{title}</h1>\n {count !== undefined && <span data-testid=\"count\">{count}</span>}\n </div>\n );\n\n const testSchema = z.object({\n title: z.string(),\n count: z.number().optional(),\n });\n\n beforeEach(() => {\n jest.clearAllMocks();\n // Reset mock implementations\n mockAddInteractableComponent.mockReturnValue(\"mock-id-123\");\n mockGetInteractableComponent.mockReturnValue(null);\n mockGetInteractableComponentsByName.mockReturnValue([]);\n });\n\n it(\"should render the wrapped component with provided props\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Hello\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"42\");\n });\n\n it(\"should set displayName correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(TestComponent)\",\n );\n });\n\n it(\"should handle components without displayName\", () => {\n const AnonymousComponent = () => <div>Anonymous</div>;\n\n const InteractableComponent = withTamboInteractable(AnonymousComponent, {\n componentName: \"AnonymousComponent\",\n description: \"An anonymous component\",\n });\n\n // Anonymous components get their name from the function name\n expect(InteractableComponent.displayName).toBe(\n \"withTamboInteractable(AnonymousComponent)\",\n );\n });\n\n it(\"should provide TamboMessageProvider with interactable metadata\", async () => {\n // Child component that uses the context\n const ContextConsumer = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"interactable-id\">{component?.interactableId}</span>\n <span data-testid=\"component-name\">{component?.componentName}</span>\n <span data-testid=\"description\">{component?.description}</span>\n </div>\n );\n };\n\n // Wrap TestComponent to include ContextConsumer\n const TestComponentWithConsumer: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <ContextConsumer />\n </div>\n );\n\n const InteractableWithConsumer = withTamboInteractable(\n TestComponentWithConsumer,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithConsumer title=\"Hello\" />\n </TamboInteractableProvider>,\n );\n\n // Wait for the component to register and render\n await waitFor(() => {\n expect(screen.getByTestId(\"interactable-id\")).toHaveTextContent(\n \"mock-id-123\",\n );\n });\n\n expect(screen.getByTestId(\"component-name\")).toHaveTextContent(\n \"TestComponent\",\n );\n expect(screen.getByTestId(\"description\")).toHaveTextContent(\n \"A test component\",\n );\n });\n\n it(\"should create minimal message with correct structure\", async () => {\n // Child component that checks the message structure\n const MessageChecker = () => {\n const component = useTamboCurrentComponent();\n return (\n <div>\n <span data-testid=\"has-component-name\">\n {component?.componentName ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-props\">{component?.props ? \"yes\" : \"no\"}</span>\n <span data-testid=\"has-interactable-id\">\n {component?.interactableId ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-description\">\n {component?.description ? \"yes\" : \"no\"}\n </span>\n </div>\n );\n };\n\n const TestComponentWithChecker: React.FC<TestComponentProps> = (props) => (\n <div>\n <TestComponent {...props} />\n <MessageChecker />\n </div>\n );\n\n const InteractableWithChecker = withTamboInteractable(\n TestComponentWithChecker,\n {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n },\n );\n\n render(\n <TamboInteractableProvider>\n <InteractableWithChecker title=\"Hello\" count={42} />\n </TamboInteractableProvider>,\n );\n\n await waitFor(() => {\n expect(screen.getByTestId(\"has-component-name\")).toHaveTextContent(\"yes\");\n });\n\n expect(screen.getByTestId(\"has-props\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-interactable-id\")).toHaveTextContent(\"yes\");\n expect(screen.getByTestId(\"has-description\")).toHaveTextContent(\"yes\");\n });\n\n it(\"should pass through all component props correctly\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n propsSchema: testSchema,\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test Title\" count={100} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test Title\");\n expect(screen.getByTestId(\"count\")).toHaveTextContent(\"100\");\n });\n\n it(\"should filter out interactable-specific props from component props\", () => {\n interface ExtendedProps extends TestComponentProps {\n onInteractableReady?: (id: string) => void;\n onPropsUpdate?: (props: Record<string, any>) => void;\n }\n\n const ExtendedComponent: React.FC<ExtendedProps> = ({\n title,\n onInteractableReady,\n onPropsUpdate,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"has-ready\">\n {onInteractableReady ? \"yes\" : \"no\"}\n </span>\n <span data-testid=\"has-update\">{onPropsUpdate ? \"yes\" : \"no\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(ExtendedComponent, {\n componentName: \"ExtendedComponent\",\n description: \"An extended component\",\n });\n\n const mockReady = jest.fn();\n const mockUpdate = jest.fn();\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent\n title=\"Test\"\n onInteractableReady={mockReady}\n onPropsUpdate={mockUpdate}\n />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n // These props should be filtered out\n expect(screen.getByTestId(\"has-ready\")).toHaveTextContent(\"no\");\n expect(screen.getByTestId(\"has-update\")).toHaveTextContent(\"no\");\n });\n\n it(\"should pass annotations config to addInteractableComponent\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n annotations: { tamboStreamableHint: false },\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test\" />\n </TamboInteractableProvider>,\n );\n\n expect(mockAddInteractableComponent).toHaveBeenCalledWith(\n expect.objectContaining({\n annotations: { tamboStreamableHint: false },\n }),\n );\n });\n\n it(\"should work without propsSchema\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"No Schema\" />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"No Schema\");\n });\n\n it(\"should render before interactable ID is set\", () => {\n const InteractableComponent = withTamboInteractable(TestComponent, {\n componentName: \"TestComponent\",\n description: \"A test component\",\n });\n\n const { container } = render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Early Render\" />\n </TamboInteractableProvider>,\n );\n\n // Component should render even before ID is available\n expect(\n container.querySelector('[data-testid=\"title\"]'),\n ).toBeInTheDocument();\n });\n\n it(\"should handle null/undefined values in props\", () => {\n interface NullableProps {\n title: string;\n optional?: string;\n nullable: string | null;\n }\n\n const NullableComponent: React.FC<NullableProps> = ({\n title,\n optional,\n nullable,\n }) => (\n <div>\n <span data-testid=\"title\">{title}</span>\n <span data-testid=\"optional\">{optional ?? \"undefined\"}</span>\n <span data-testid=\"nullable\">{nullable ?? \"null\"}</span>\n </div>\n );\n\n const InteractableComponent = withTamboInteractable(NullableComponent, {\n componentName: \"NullableComponent\",\n description: \"A component with nullable props\",\n });\n\n render(\n <TamboInteractableProvider>\n <InteractableComponent title=\"Test\" nullable={null} />\n </TamboInteractableProvider>,\n );\n\n expect(screen.getByTestId(\"title\")).toHaveTextContent(\"Test\");\n expect(screen.getByTestId(\"optional\")).toHaveTextContent(\"undefined\");\n expect(screen.getByTestId(\"nullable\")).toHaveTextContent(\"null\");\n });\n});\n"]}
@@ -39,6 +39,9 @@ describe("useTamboVoice", () => {
39
39
  client: mockClient,
40
40
  queryClient,
41
41
  isUpdatingToken: false,
42
+ tokenExchangeError: null,
43
+ userToken: undefined,
44
+ hasValidToken: false,
42
45
  } },
43
46
  react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient }, children)));
44
47
  Wrapper.displayName = "TestWrapper";
@@ -1 +1 @@
1
- {"version":3,"file":"use-tambo-voice.test.js","sourceRoot":"","sources":["../../src/hooks/use-tambo-voice.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { useReactMediaRecorder } from \"react-media-recorder\";\nimport { useTamboVoice } from \"./use-tambo-voice\";\nimport { TamboClientContext } from \"../providers/tambo-client-provider\";\nimport TamboAI from \"@tambo-ai/typescript-sdk\";\n\n// Override the global mock from setupTests.ts with a controllable version\njest.mock(\"react-media-recorder\", () => ({\n useReactMediaRecorder: jest.fn(),\n}));\n\n// Mock the client provider\njest.mock(\"../providers/tambo-client-provider\", () => ({\n ...jest.requireActual(\"../providers/tambo-client-provider\"),\n useTamboClient: jest.fn(),\n}));\n\nimport { useTamboClient } from \"../providers/tambo-client-provider\";\n\n// Mock fetch globally\nconst mockFetch = jest.fn();\n\ndescribe(\"useTamboVoice\", () => {\n let previousFetch: typeof fetch;\n let mockStartRecording: jest.Mock;\n let mockStopRecording: jest.Mock;\n let mockTranscribe: jest.Mock;\n let queryClient: QueryClient;\n\n type MediaRecorderMockValue = Pick<\n ReturnType<typeof useReactMediaRecorder>,\n \"status\" | \"startRecording\" | \"stopRecording\" | \"mediaBlobUrl\" | \"error\"\n >;\n\n const createWrapper = () => {\n const mockClient = {\n beta: {\n audio: {\n transcribe: mockTranscribe,\n },\n },\n } as unknown as TamboAI;\n\n const Wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboClientContext.Provider\n value={{\n client: mockClient,\n queryClient,\n isUpdatingToken: false,\n }}\n >\n <QueryClientProvider client={queryClient}>\n {children}\n </QueryClientProvider>\n </TamboClientContext.Provider>\n );\n Wrapper.displayName = \"TestWrapper\";\n return Wrapper;\n };\n\n const setupMediaRecorderMock = (\n overrides: Partial<MediaRecorderMockValue> = {},\n ) => {\n const value: MediaRecorderMockValue = {\n status: \"idle\",\n startRecording: mockStartRecording,\n stopRecording: mockStopRecording,\n mediaBlobUrl: undefined,\n error: \"\",\n ...overrides,\n };\n jest\n .mocked(useReactMediaRecorder)\n .mockReturnValue(\n value as unknown as ReturnType<typeof useReactMediaRecorder>,\n );\n return value;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n mockFetch.mockReset();\n\n previousFetch = global.fetch;\n global.fetch = mockFetch as unknown as typeof fetch;\n\n mockStartRecording = jest.fn();\n mockStopRecording = jest.fn();\n mockTranscribe = jest.fn();\n queryClient = new QueryClient({\n defaultOptions: {\n queries: { retry: false },\n mutations: { retry: false },\n },\n });\n\n // Setup default client mock\n const mockClient = {\n beta: {\n audio: {\n transcribe: mockTranscribe,\n },\n },\n };\n jest\n .mocked(useTamboClient)\n .mockReturnValue(mockClient as unknown as TamboAI);\n\n // Setup default media recorder mock\n setupMediaRecorderMock();\n\n // Setup default fetch mock\n mockFetch.mockResolvedValue({\n blob: async () =>\n await Promise.resolve(new Blob([\"audio data\"], { type: \"audio/webm\" })),\n });\n });\n\n afterEach(() => {\n global.fetch = previousFetch;\n });\n\n describe(\"Initial State\", () => {\n it(\"should initialize with idle state and no transcript\", () => {\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.isRecording).toBe(false);\n expect(result.current.isTranscribing).toBe(false);\n expect(result.current.transcript).toBeNull();\n expect(result.current.transcriptionError).toBeNull();\n expect(result.current.mediaAccessError).toBeNull();\n });\n });\n\n describe(\"Recording Flow\", () => {\n it(\"should expose isRecording=true during active recording\", () => {\n setupMediaRecorderMock({ status: \"recording\" });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.isRecording).toBe(true);\n });\n\n it(\"should call startRecording on the media recorder\", () => {\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.startRecording();\n });\n\n expect(mockStartRecording).toHaveBeenCalled();\n });\n\n it(\"should call stopRecording on the media recorder when recording\", () => {\n setupMediaRecorderMock({ status: \"recording\" });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.stopRecording();\n });\n\n expect(mockStopRecording).toHaveBeenCalled();\n });\n\n it(\"should reset transcript when starting a new recording\", async () => {\n mockTranscribe.mockResolvedValue(\"first transcript\");\n\n // Start with completed transcription\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio1\",\n });\n\n const { result, rerender } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n // Wait for transcription to complete\n await waitFor(() => {\n expect(result.current.transcript).toBe(\"first transcript\");\n });\n\n // Now simulate starting a new recording\n setupMediaRecorderMock({ status: \"idle\" });\n rerender();\n\n act(() => {\n result.current.startRecording();\n });\n\n expect(result.current.transcript).toBeNull();\n });\n });\n\n describe(\"Transcription\", () => {\n it(\"should trigger transcription after recording stops with blob URL\", async () => {\n mockTranscribe.mockResolvedValue(\"Hello world\");\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcript).toBe(\"Hello world\");\n });\n\n expect(mockFetch).toHaveBeenCalledWith(\"blob:http://localhost/audio\");\n expect(mockTranscribe).toHaveBeenCalled();\n });\n\n it(\"should expose isTranscribing=true during API call\", async () => {\n let resolveTranscription: (value: string) => void;\n mockTranscribe.mockImplementation(\n async () =>\n await new Promise((resolve) => {\n resolveTranscription = resolve;\n }),\n );\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.isTranscribing).toBe(true);\n });\n\n // Complete the transcription\n act(() => {\n resolveTranscription!(\"transcribed text\");\n });\n\n await waitFor(() => {\n expect(result.current.isTranscribing).toBe(false);\n });\n });\n });\n\n describe(\"Error Handling\", () => {\n it(\"should expose mediaAccessError when microphone access fails\", () => {\n setupMediaRecorderMock({\n error: \"Permission denied\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.mediaAccessError).toBe(\"Permission denied\");\n });\n\n it(\"should expose transcriptionError when API call fails\", async () => {\n mockTranscribe.mockRejectedValue(\n new Error(\"Transcription service unavailable\"),\n );\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcriptionError).toBe(\n \"Transcription service unavailable\",\n );\n });\n\n expect(result.current.isTranscribing).toBe(false);\n });\n\n it(\"should handle blob fetch failure gracefully\", async () => {\n mockFetch.mockRejectedValue(new Error(\"Network error\"));\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcriptionError).toBe(\"Network error\");\n });\n\n expect(result.current.isTranscribing).toBe(false);\n expect(result.current.transcript).toBeNull();\n });\n });\n});\n"]}
1
+ {"version":3,"file":"use-tambo-voice.test.js","sourceRoot":"","sources":["../../src/hooks/use-tambo-voice.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { act, renderHook, waitFor } from \"@testing-library/react\";\nimport React from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { useReactMediaRecorder } from \"react-media-recorder\";\nimport { useTamboVoice } from \"./use-tambo-voice\";\nimport { TamboClientContext } from \"../providers/tambo-client-provider\";\nimport TamboAI from \"@tambo-ai/typescript-sdk\";\n\n// Override the global mock from setupTests.ts with a controllable version\njest.mock(\"react-media-recorder\", () => ({\n useReactMediaRecorder: jest.fn(),\n}));\n\n// Mock the client provider\njest.mock(\"../providers/tambo-client-provider\", () => ({\n ...jest.requireActual(\"../providers/tambo-client-provider\"),\n useTamboClient: jest.fn(),\n}));\n\nimport { useTamboClient } from \"../providers/tambo-client-provider\";\n\n// Mock fetch globally\nconst mockFetch = jest.fn();\n\ndescribe(\"useTamboVoice\", () => {\n let previousFetch: typeof fetch;\n let mockStartRecording: jest.Mock;\n let mockStopRecording: jest.Mock;\n let mockTranscribe: jest.Mock;\n let queryClient: QueryClient;\n\n type MediaRecorderMockValue = Pick<\n ReturnType<typeof useReactMediaRecorder>,\n \"status\" | \"startRecording\" | \"stopRecording\" | \"mediaBlobUrl\" | \"error\"\n >;\n\n const createWrapper = () => {\n const mockClient = {\n beta: {\n audio: {\n transcribe: mockTranscribe,\n },\n },\n } as unknown as TamboAI;\n\n const Wrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboClientContext.Provider\n value={{\n client: mockClient,\n queryClient,\n isUpdatingToken: false,\n tokenExchangeError: null,\n userToken: undefined,\n hasValidToken: false,\n }}\n >\n <QueryClientProvider client={queryClient}>\n {children}\n </QueryClientProvider>\n </TamboClientContext.Provider>\n );\n Wrapper.displayName = \"TestWrapper\";\n return Wrapper;\n };\n\n const setupMediaRecorderMock = (\n overrides: Partial<MediaRecorderMockValue> = {},\n ) => {\n const value: MediaRecorderMockValue = {\n status: \"idle\",\n startRecording: mockStartRecording,\n stopRecording: mockStopRecording,\n mediaBlobUrl: undefined,\n error: \"\",\n ...overrides,\n };\n jest\n .mocked(useReactMediaRecorder)\n .mockReturnValue(\n value as unknown as ReturnType<typeof useReactMediaRecorder>,\n );\n return value;\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n\n mockFetch.mockReset();\n\n previousFetch = global.fetch;\n global.fetch = mockFetch as unknown as typeof fetch;\n\n mockStartRecording = jest.fn();\n mockStopRecording = jest.fn();\n mockTranscribe = jest.fn();\n queryClient = new QueryClient({\n defaultOptions: {\n queries: { retry: false },\n mutations: { retry: false },\n },\n });\n\n // Setup default client mock\n const mockClient = {\n beta: {\n audio: {\n transcribe: mockTranscribe,\n },\n },\n };\n jest\n .mocked(useTamboClient)\n .mockReturnValue(mockClient as unknown as TamboAI);\n\n // Setup default media recorder mock\n setupMediaRecorderMock();\n\n // Setup default fetch mock\n mockFetch.mockResolvedValue({\n blob: async () =>\n await Promise.resolve(new Blob([\"audio data\"], { type: \"audio/webm\" })),\n });\n });\n\n afterEach(() => {\n global.fetch = previousFetch;\n });\n\n describe(\"Initial State\", () => {\n it(\"should initialize with idle state and no transcript\", () => {\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.isRecording).toBe(false);\n expect(result.current.isTranscribing).toBe(false);\n expect(result.current.transcript).toBeNull();\n expect(result.current.transcriptionError).toBeNull();\n expect(result.current.mediaAccessError).toBeNull();\n });\n });\n\n describe(\"Recording Flow\", () => {\n it(\"should expose isRecording=true during active recording\", () => {\n setupMediaRecorderMock({ status: \"recording\" });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.isRecording).toBe(true);\n });\n\n it(\"should call startRecording on the media recorder\", () => {\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.startRecording();\n });\n\n expect(mockStartRecording).toHaveBeenCalled();\n });\n\n it(\"should call stopRecording on the media recorder when recording\", () => {\n setupMediaRecorderMock({ status: \"recording\" });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n act(() => {\n result.current.stopRecording();\n });\n\n expect(mockStopRecording).toHaveBeenCalled();\n });\n\n it(\"should reset transcript when starting a new recording\", async () => {\n mockTranscribe.mockResolvedValue(\"first transcript\");\n\n // Start with completed transcription\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio1\",\n });\n\n const { result, rerender } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n // Wait for transcription to complete\n await waitFor(() => {\n expect(result.current.transcript).toBe(\"first transcript\");\n });\n\n // Now simulate starting a new recording\n setupMediaRecorderMock({ status: \"idle\" });\n rerender();\n\n act(() => {\n result.current.startRecording();\n });\n\n expect(result.current.transcript).toBeNull();\n });\n });\n\n describe(\"Transcription\", () => {\n it(\"should trigger transcription after recording stops with blob URL\", async () => {\n mockTranscribe.mockResolvedValue(\"Hello world\");\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcript).toBe(\"Hello world\");\n });\n\n expect(mockFetch).toHaveBeenCalledWith(\"blob:http://localhost/audio\");\n expect(mockTranscribe).toHaveBeenCalled();\n });\n\n it(\"should expose isTranscribing=true during API call\", async () => {\n let resolveTranscription: (value: string) => void;\n mockTranscribe.mockImplementation(\n async () =>\n await new Promise((resolve) => {\n resolveTranscription = resolve;\n }),\n );\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.isTranscribing).toBe(true);\n });\n\n // Complete the transcription\n act(() => {\n resolveTranscription!(\"transcribed text\");\n });\n\n await waitFor(() => {\n expect(result.current.isTranscribing).toBe(false);\n });\n });\n });\n\n describe(\"Error Handling\", () => {\n it(\"should expose mediaAccessError when microphone access fails\", () => {\n setupMediaRecorderMock({\n error: \"Permission denied\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.mediaAccessError).toBe(\"Permission denied\");\n });\n\n it(\"should expose transcriptionError when API call fails\", async () => {\n mockTranscribe.mockRejectedValue(\n new Error(\"Transcription service unavailable\"),\n );\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcriptionError).toBe(\n \"Transcription service unavailable\",\n );\n });\n\n expect(result.current.isTranscribing).toBe(false);\n });\n\n it(\"should handle blob fetch failure gracefully\", async () => {\n mockFetch.mockRejectedValue(new Error(\"Network error\"));\n\n setupMediaRecorderMock({\n status: \"stopped\",\n mediaBlobUrl: \"blob:http://localhost/audio\",\n });\n\n const { result } = renderHook(() => useTamboVoice(), {\n wrapper: createWrapper(),\n });\n\n await waitFor(() => {\n expect(result.current.transcriptionError).toBe(\"Network error\");\n });\n\n expect(result.current.isTranscribing).toBe(false);\n expect(result.current.transcript).toBeNull();\n });\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-hooks.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAEzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKvD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAoBzE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,iBAAiB,GACvB,KAAK,IAAI,gBAAgB,CAE3B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;gBA/D3C,kBAAkB;;WA2HnB,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAb7B;AAmDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,GAChB,MAAM,IAAI,kBAAkB,CAE9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0ClC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM;;WArH9C,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAwO7B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;iBAoElE"}
1
+ {"version":3,"file":"mcp-hooks.d.ts","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAKvD,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAEf,MAAM,sBAAsB,CAAC;AAkC9B,MAAM,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,WAAW,eAAe;IAE9B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;AAoBzE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,iBAAiB,GACvB,KAAK,IAAI,gBAAgB,CAE3B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;gBA/D3C,kBAAkB;;WAoInB,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAb7B;AAmDD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,GAChB,MAAM,IAAI,kBAAkB,CAE9B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0ClC;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM;;WArH9C,KAAK,GAAG,IAAI;YACX,KAAK,EAAE;eACJ,OAAO;eACP,OAAO;aACT,OAAO;cACN,OAAO;kBACH,OAAO;gBACT,OAAO;eACR,OAAO;aACT,MAAM,OAAO,CAAC,IAAI,CAAC;EAiP7B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;iBAoElE"}
@@ -39,11 +39,43 @@ exports.isConnectedMcpServer = isConnectedMcpServer;
39
39
  exports.useTamboMcpPrompt = useTamboMcpPrompt;
40
40
  exports.useTamboMcpResourceList = useTamboMcpResourceList;
41
41
  exports.useTamboMcpResource = useTamboMcpResource;
42
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
42
43
  const React = __importStar(require("react"));
43
44
  const hooks_1 = require("../hooks");
44
45
  const tambo_registry_provider_1 = require("../providers/tambo-registry-provider");
45
46
  const mcp_constants_1 = require("./mcp-constants");
46
47
  const tambo_mcp_provider_1 = require("./tambo-mcp-provider");
48
+ /**
49
+ * Check if an error is an MCP MethodNotFound error (-32601).
50
+ * This error occurs when a server doesn't support a particular method.
51
+ */
52
+ function isMethodNotFoundError(error) {
53
+ return error instanceof types_js_1.McpError && error.code === types_js_1.ErrorCode.MethodNotFound;
54
+ }
55
+ /**
56
+ * Check if an MCP server supports listing prompts.
57
+ * Returns true if capabilities are unknown (undefined) to maintain backward compatibility,
58
+ * since some servers don't properly report capabilities.
59
+ */
60
+ function serverSupportsPrompts(server) {
61
+ const capabilities = server.client.getServerCapabilities?.();
62
+ // If capabilities are undefined, assume the server supports prompts (optimistic approach)
63
+ if (capabilities === undefined)
64
+ return true;
65
+ return capabilities.prompts != null;
66
+ }
67
+ /**
68
+ * Check if an MCP server supports listing resources.
69
+ * Returns true if capabilities are unknown (undefined) to maintain backward compatibility,
70
+ * since some servers don't properly report capabilities.
71
+ */
72
+ function serverSupportsResources(server) {
73
+ const capabilities = server.client.getServerCapabilities?.();
74
+ // If capabilities are undefined, assume the server supports resources (optimistic approach)
75
+ if (capabilities === undefined)
76
+ return true;
77
+ return capabilities.resources != null;
78
+ }
47
79
  function toPublicResourceEntry(entry) {
48
80
  if (entry.server === null) {
49
81
  const { isDynamic: _isDynamic, ...publicEntry } = entry;
@@ -76,14 +108,25 @@ function useTamboMcpPromptList(search) {
76
108
  // Fast path: if this server doesn't have a client, skip work
77
109
  if (!isConnectedMcpServer(mcpServer))
78
110
  return [];
79
- const result = await mcpServer.client.client.listPrompts();
80
- const prompts = result?.prompts ?? [];
81
- // Return prompts without prefixes - we'll apply prefixing in combine
82
- const promptsEntries = prompts.map((prompt) => ({
83
- server: mcpServer,
84
- prompt,
85
- }));
86
- return promptsEntries;
111
+ // Skip if server doesn't support prompts capability
112
+ if (!serverSupportsPrompts(mcpServer))
113
+ return [];
114
+ try {
115
+ const result = await mcpServer.client.client.listPrompts();
116
+ const prompts = result?.prompts ?? [];
117
+ // Return prompts without prefixes - we'll apply prefixing in combine
118
+ const promptsEntries = prompts.map((prompt) => ({
119
+ server: mcpServer,
120
+ prompt,
121
+ }));
122
+ return promptsEntries;
123
+ }
124
+ catch (error) {
125
+ // Gracefully handle MethodNotFound - server doesn't support this method
126
+ if (isMethodNotFoundError(error))
127
+ return [];
128
+ throw error;
129
+ }
87
130
  },
88
131
  })),
89
132
  combine: (results) => {
@@ -214,14 +257,25 @@ function useTamboMcpResourceList(search) {
214
257
  // Fast path: if this server doesn't have a client, skip work
215
258
  if (!isConnectedMcpServer(mcpServer))
216
259
  return [];
217
- const result = await mcpServer.client.client.listResources();
218
- const resources = result?.resources ?? [];
219
- // Return resources without prefixes - we'll apply prefixing in combine
220
- const resourceEntries = resources.map((resource) => ({
221
- server: mcpServer,
222
- resource,
223
- }));
224
- return resourceEntries;
260
+ // Skip if server doesn't support resources capability
261
+ if (!serverSupportsResources(mcpServer))
262
+ return [];
263
+ try {
264
+ const result = await mcpServer.client.client.listResources();
265
+ const resources = result?.resources ?? [];
266
+ // Return resources without prefixes - we'll apply prefixing in combine
267
+ const resourceEntries = resources.map((resource) => ({
268
+ server: mcpServer,
269
+ resource,
270
+ }));
271
+ return resourceEntries;
272
+ }
273
+ catch (error) {
274
+ // Gracefully handle MethodNotFound - server doesn't support this method
275
+ if (isMethodNotFoundError(error))
276
+ return [];
277
+ throw error;
278
+ }
225
279
  },
226
280
  })),
227
281
  // Dynamic resource source query (if exists) - search IS in queryKey to allow dynamic generation
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-hooks.js","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n GetPromptResult,\n type ListPromptsResult,\n type ListResourcesResult,\n type ReadResourceResult,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { UseQueryResult } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { useTamboQueries, useTamboQuery } from \"../hooks\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { REGISTRY_SERVER_KEY } from \"./mcp-constants\";\nimport {\n type ConnectedMcpServer,\n type McpServer,\n useTamboMcpServers,\n} from \"./tambo-mcp-provider\";\n\nexport type ListPromptItem = ListPromptsResult[\"prompts\"][number];\nexport interface ListPromptEntry {\n // Only connected servers produce prompt entries, so expose the connected type\n server: ConnectedMcpServer;\n prompt: ListPromptItem;\n}\n\nexport type ListResourceItem = ListResourcesResult[\"resources\"][number];\n\n/**\n * Registry resource entry - resources from the local registry (not MCP servers).\n *\n * These entries always have `server === null`.\n */\nexport interface RegistryResourceEntry {\n server: null;\n resource: ListResourceItem;\n}\n\n/**\n * MCP server resource entry - resources from connected MCP servers.\n */\nexport interface McpResourceEntry {\n server: ConnectedMcpServer;\n resource: ListResourceItem;\n}\n\n/**\n * Union type for all resource entries returned by `useTamboMcpResourceList`.\n */\nexport type ListResourceEntry = RegistryResourceEntry | McpResourceEntry;\n\ntype InternalRegistryResourceEntry = RegistryResourceEntry & {\n isDynamic: boolean;\n};\n\ntype InternalListResourceEntry =\n | McpResourceEntry\n | InternalRegistryResourceEntry;\n\nfunction toPublicResourceEntry(\n entry: InternalListResourceEntry,\n): ListResourceEntry {\n if (entry.server === null) {\n const { isDynamic: _isDynamic, ...publicEntry } = entry;\n return publicEntry;\n }\n return entry;\n}\n\n/**\n * Type guard for narrowing a `ListResourceEntry` to an MCP-backed resource.\n * @param entry - The resource entry to check\n * @returns True if the entry is from an MCP server, false if it's from the registry\n */\nexport function isMcpResourceEntry(\n entry: ListResourceEntry,\n): entry is McpResourceEntry {\n return entry.server !== null && isConnectedMcpServer(entry.server);\n}\n\n/**\n * Hook to get the prompts for all the registered MCP servers.\n * @param search - Optional search string to filter prompts by name (case-insensitive).\n * @returns The prompts for the MCP servers, including the server that the prompt was found on.\n */\nexport function useTamboMcpPromptList(search?: string) {\n const mcpServers = useTamboMcpServers();\n\n const queries = useTamboQueries({\n queries: mcpServers.map((mcpServer) => ({\n // search is NOT in queryKey - we filter locally after fetching\n queryKey: [\"mcp-prompts\", mcpServer.key],\n // Only run for connected servers that have a client\n enabled: isConnectedMcpServer(mcpServer),\n queryFn: async (): Promise<ListPromptEntry[]> => {\n // Fast path: if this server doesn't have a client, skip work\n if (!isConnectedMcpServer(mcpServer)) return [];\n\n const result = await mcpServer.client.client.listPrompts();\n const prompts: ListPromptItem[] = result?.prompts ?? [];\n // Return prompts without prefixes - we'll apply prefixing in combine\n const promptsEntries = prompts.map((prompt) => ({\n server: mcpServer,\n prompt,\n }));\n return promptsEntries;\n },\n })),\n combine: (results) => {\n const combined = combineArrayResults(results);\n\n // Always apply serverKey prefix to MCP prompts (breaking change for consistency with resources)\n // This ensures clear separation between local and remote prompts\n return {\n ...combined,\n data: combined.data.map((entry) => ({\n ...entry,\n prompt: {\n ...entry.prompt,\n name: `${entry.server.serverKey}:${entry.prompt.name}`,\n },\n })),\n };\n },\n });\n\n // Filter results by search string - runs on every search change (not just query completion)\n const filteredData = React.useMemo(() => {\n if (!search) return queries.data;\n\n const normalizedSearch = search.toLowerCase();\n return queries.data.filter((entry) => {\n const name = entry.prompt.name?.toLowerCase() ?? \"\";\n return name.includes(normalizedSearch);\n });\n }, [queries.data, search]);\n\n return {\n ...queries,\n data: filteredData,\n };\n}\n// TODO: find a more general place for this\nfunction combineArrayResults<T>(results: UseQueryResult<T[]>[]): {\n data: T[];\n error: Error | null;\n errors: Error[];\n isPending: boolean;\n isSuccess: boolean;\n isError: boolean;\n isPaused: boolean;\n isRefetching: boolean;\n isFetching: boolean;\n isLoading: boolean;\n refetch: () => Promise<void>;\n} {\n const errors = results\n .filter((result) => result.isError)\n .map((result) => result.error);\n\n // Treat queries that are idle (disabled) as non-blocking for aggregate status\n const enabledish = results.filter(\n (r) => r.fetchStatus !== \"idle\" || r.isSuccess || r.isError,\n );\n\n return {\n // Prefer flatMap to avoid extra intermediate arrays\n data: results.flatMap((result) =>\n result.isSuccess && Array.isArray(result.data) ? result.data : [],\n ),\n // Preserve a single error for compatibility and expose the full list for diagnostics\n error: errors[0] ?? null,\n errors,\n isPending: enabledish.some((result) => result.isPending),\n isSuccess:\n enabledish.length > 0 && enabledish.every((result) => result.isSuccess),\n isError: errors.length > 0,\n isPaused: enabledish.some((result) => result.isPaused),\n isRefetching: enabledish.some((result) => result.isRefetching),\n isFetching: enabledish.some((result) => result.isFetching),\n isLoading: enabledish.some((result) => result.isLoading),\n // Aggregate refetch to trigger all underlying queries\n refetch: async () => {\n await Promise.all(\n results.map(async (r) => {\n await r.refetch();\n }),\n );\n },\n };\n}\n\n/**\n * Type guard for narrowing McpServer to ConnectedMcpServer.\n * A connected server has a non-null client.\n * @param server - The MCP server to check\n * @returns True if the server is connected, false otherwise\n */\nexport function isConnectedMcpServer(\n server: McpServer,\n): server is ConnectedMcpServer {\n return \"client\" in server && server.client != null;\n}\n\n/**\n * Hook to get the prompt for the specified name.\n * @param promptName - The name of the prompt to get. Can be prefixed with serverKey (e.g., \"linear:issue\") or unprefixed.\n * @param args - The arguments to pass to the prompt.\n * @returns The prompt for the specified name.\n */\nexport function useTamboMcpPrompt(\n promptName: string | undefined,\n args: Record<string, string> = {},\n) {\n // figure out which server has the prompt\n const { data: promptEntries } = useTamboMcpPromptList();\n const promptEntry = promptEntries?.find(\n (prompt) => prompt.prompt.name === promptName,\n );\n // Use the stable server key (and the server instance itself) instead of brittle\n // name/url/transport matching.\n const mcpServer = promptEntry?.server;\n\n // Strip the prefix to get the original prompt name for the MCP server call\n const originalPromptName = promptName?.includes(\":\")\n ? promptName.split(\":\").slice(1).join(\":\")\n : promptName;\n\n // Canonicalize args to avoid unstable cache keys from object identity/order\n const sortedArgsEntries = Object.keys(args)\n .sort()\n .map((k) => [k, args[k]] as const);\n return useTamboQuery({\n // Include server identity and sorted args to prevent stale cache hits\n queryKey: [\"mcp-prompt\", promptName, mcpServer?.key, sortedArgsEntries],\n // Only run when we have a prompt name and a connected server\n enabled: Boolean(\n promptName && mcpServer && isConnectedMcpServer(mcpServer),\n ),\n queryFn: async (): Promise<GetPromptResult | null> => {\n if (\n !originalPromptName ||\n !mcpServer ||\n !isConnectedMcpServer(mcpServer)\n ) {\n return null;\n }\n const result = await mcpServer.client.client.getPrompt({\n name: originalPromptName,\n arguments: args,\n });\n return result ?? null; // return null because react-query doesn't like undefined results\n },\n });\n}\n\n/**\n * Hook to get the resources for all the registered MCP servers and registry.\n * @param search - Optional search string. For MCP servers, results are filtered locally after fetching.\n * For registry dynamic sources, the search is passed to listResources(search) for dynamic generation.\n * @returns The resources from MCP servers and the local registry, including the server that the resource was found on (null for registry resources).\n */\nexport function useTamboMcpResourceList(search?: string) {\n const mcpServers = useTamboMcpServers();\n const { resources: staticResources, resourceSource } = useTamboRegistry();\n\n // Build list of queries: MCP servers + optional dynamic resource source\n const queriesToRun = [\n // MCP server queries - search is NOT in queryKey so queries don't re-run on search change\n ...mcpServers.map((mcpServer) => ({\n queryKey: [\"mcp-resources\", mcpServer.key],\n // Only run for connected servers that have a client\n enabled: isConnectedMcpServer(mcpServer),\n queryFn: async (): Promise<McpResourceEntry[]> => {\n // Fast path: if this server doesn't have a client, skip work\n if (!isConnectedMcpServer(mcpServer)) return [];\n\n const result = await mcpServer.client.client.listResources();\n const resources: ListResourceItem[] = result?.resources ?? [];\n // Return resources without prefixes - we'll apply prefixing in combine\n const resourceEntries: McpResourceEntry[] = resources.map(\n (resource) => ({\n server: mcpServer,\n resource,\n }),\n );\n return resourceEntries;\n },\n })),\n // Dynamic resource source query (if exists) - search IS in queryKey to allow dynamic generation\n ...(resourceSource\n ? [\n {\n queryKey: [\"registry-resources\", \"dynamic\", search],\n enabled: true,\n queryFn: async (): Promise<InternalRegistryResourceEntry[]> => {\n if (!resourceSource) return [];\n const resources = await resourceSource.listResources(search);\n return resources.map((resource) => ({\n server: null,\n resource,\n isDynamic: true,\n }));\n },\n },\n ]\n : []),\n ];\n\n const queries = useTamboQueries({\n queries: queriesToRun,\n combine: (results) => {\n // Type assertion needed because queries can return different entry types\n const combined = combineArrayResults(\n results as UseQueryResult<InternalListResourceEntry[]>[],\n );\n\n // Add static registry resources (no query needed)\n const staticEntries: InternalRegistryResourceEntry[] =\n staticResources.map((resource) => ({\n server: null,\n resource,\n isDynamic: false,\n }));\n\n // Merge static resources with query results (registry resources first)\n const allData = [...staticEntries, ...combined.data];\n\n // Apply serverKey prefix to ALL resources for unified @serverKey:uri format\n // Registry resources get REGISTRY_SERVER_KEY prefix, MCP resources get their serverKey\n const prefixedData = allData.map((entry) => {\n if (entry.server === null) {\n // Registry resource - prefix with REGISTRY_SERVER_KEY\n return {\n ...entry,\n resource: {\n ...entry.resource,\n uri: `${REGISTRY_SERVER_KEY}:${entry.resource.uri}`,\n },\n };\n }\n // MCP resource - always prefix with serverKey\n return {\n ...entry,\n resource: {\n ...entry.resource,\n uri: `${entry.server.serverKey}:${entry.resource.uri}`,\n },\n };\n });\n\n return {\n ...combined,\n data: prefixedData,\n };\n },\n });\n\n // Filter results by search string - runs on every search change (not just query completion)\n // - MCP resources are filtered locally\n // - Static registry resources are filtered locally\n // - Dynamic registry resources are already filtered by listResources(search)\n const filteredData = React.useMemo((): InternalListResourceEntry[] => {\n if (!search) return queries.data;\n\n const normalizedSearch = search.toLowerCase();\n return queries.data.filter((entry) => {\n if (entry.server === null && entry.isDynamic) {\n return true;\n }\n\n const name = entry.resource.name?.toLowerCase() ?? \"\";\n const uri = entry.resource.uri.toLowerCase();\n return name.includes(normalizedSearch) || uri.includes(normalizedSearch);\n });\n }, [queries.data, search]);\n\n const publicData = React.useMemo(\n () => filteredData.map(toPublicResourceEntry),\n [filteredData],\n );\n\n return {\n ...queries,\n data: publicData,\n };\n}\n\n/**\n * Hook to get the resource for the specified URI.\n * @param resourceUri - The URI of the resource to get. Must be prefixed:\n * - MCP resources: prefixed with serverKey (e.g., \"linear:file://foo\")\n * - Registry resources: prefixed with \"registry:\" (e.g., \"registry:file://bar\")\n * @returns The resource for the specified URI.\n */\nexport function useTamboMcpResource(resourceUri: string | undefined) {\n const { resourceSource } = useTamboRegistry();\n const { data: resourceEntries } = useTamboMcpResourceList();\n\n // Find which server/source has the resource\n const resourceEntry = resourceEntries?.find(\n (entry) => entry.resource.uri === resourceUri,\n );\n\n // Determine if this is a registry resource or MCP resource\n const isRegistryResource = resourceEntry?.server === null;\n const mcpServer = resourceEntry?.server ?? null;\n\n // Check if the URI has the registry prefix\n const hasRegistryPrefix = Boolean(\n resourceUri?.startsWith(`${REGISTRY_SERVER_KEY}:`),\n );\n\n // Strip the prefix to get the original resource URI for fetching\n let originalResourceUri: string | undefined;\n if (isRegistryResource || hasRegistryPrefix) {\n const prefixLen = REGISTRY_SERVER_KEY.length + 1; // +1 for the colon\n originalResourceUri = resourceUri?.slice(prefixLen);\n } else if (mcpServer) {\n const prefixLen = mcpServer.serverKey.length + 1; // +1 for the colon\n originalResourceUri = resourceUri?.slice(prefixLen);\n }\n\n // Check if we can fetch this resource\n const hasRegistrySource = resourceSource != null;\n const hasConnectedMcpServer =\n mcpServer != null && isConnectedMcpServer(mcpServer);\n const canFetchFromRegistry =\n hasRegistrySource && (isRegistryResource || hasRegistryPrefix);\n const canFetchResource = Boolean(\n resourceUri && (canFetchFromRegistry || hasConnectedMcpServer),\n );\n\n const locationKey =\n isRegistryResource || hasRegistryPrefix\n ? REGISTRY_SERVER_KEY\n : mcpServer?.key;\n\n return useTamboQuery({\n queryKey: [\"resource\", resourceUri, locationKey],\n enabled: canFetchResource,\n queryFn: async (): Promise<ReadResourceResult | null> => {\n if (!originalResourceUri) {\n return null;\n }\n\n // Registry resource: use resourceSource.getResource\n if (resourceSource && (isRegistryResource || hasRegistryPrefix)) {\n const result = await resourceSource.getResource(originalResourceUri);\n return result ?? null;\n }\n\n // MCP resource: use MCP client\n if (mcpServer && isConnectedMcpServer(mcpServer)) {\n const result = await mcpServer.client.client.readResource({\n uri: originalResourceUri,\n });\n return result ?? null;\n }\n\n return null;\n },\n });\n}\n"]}
1
+ {"version":3,"file":"mcp-hooks.js","sourceRoot":"","sources":["../../src/mcp/mcp-hooks.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ErrorCode,\n GetPromptResult,\n type ListPromptsResult,\n type ListResourcesResult,\n McpError,\n type ReadResourceResult,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { UseQueryResult } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { useTamboQueries, useTamboQuery } from \"../hooks\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { REGISTRY_SERVER_KEY } from \"./mcp-constants\";\nimport {\n type ConnectedMcpServer,\n type McpServer,\n useTamboMcpServers,\n} from \"./tambo-mcp-provider\";\n\n/**\n * Check if an error is an MCP MethodNotFound error (-32601).\n * This error occurs when a server doesn't support a particular method.\n */\nfunction isMethodNotFoundError(error: unknown): boolean {\n return error instanceof McpError && error.code === ErrorCode.MethodNotFound;\n}\n\n/**\n * Check if an MCP server supports listing prompts.\n * Returns true if capabilities are unknown (undefined) to maintain backward compatibility,\n * since some servers don't properly report capabilities.\n */\nfunction serverSupportsPrompts(server: ConnectedMcpServer): boolean {\n const capabilities = server.client.getServerCapabilities?.();\n // If capabilities are undefined, assume the server supports prompts (optimistic approach)\n if (capabilities === undefined) return true;\n return capabilities.prompts != null;\n}\n\n/**\n * Check if an MCP server supports listing resources.\n * Returns true if capabilities are unknown (undefined) to maintain backward compatibility,\n * since some servers don't properly report capabilities.\n */\nfunction serverSupportsResources(server: ConnectedMcpServer): boolean {\n const capabilities = server.client.getServerCapabilities?.();\n // If capabilities are undefined, assume the server supports resources (optimistic approach)\n if (capabilities === undefined) return true;\n return capabilities.resources != null;\n}\n\nexport type ListPromptItem = ListPromptsResult[\"prompts\"][number];\nexport interface ListPromptEntry {\n // Only connected servers produce prompt entries, so expose the connected type\n server: ConnectedMcpServer;\n prompt: ListPromptItem;\n}\n\nexport type ListResourceItem = ListResourcesResult[\"resources\"][number];\n\n/**\n * Registry resource entry - resources from the local registry (not MCP servers).\n *\n * These entries always have `server === null`.\n */\nexport interface RegistryResourceEntry {\n server: null;\n resource: ListResourceItem;\n}\n\n/**\n * MCP server resource entry - resources from connected MCP servers.\n */\nexport interface McpResourceEntry {\n server: ConnectedMcpServer;\n resource: ListResourceItem;\n}\n\n/**\n * Union type for all resource entries returned by `useTamboMcpResourceList`.\n */\nexport type ListResourceEntry = RegistryResourceEntry | McpResourceEntry;\n\ntype InternalRegistryResourceEntry = RegistryResourceEntry & {\n isDynamic: boolean;\n};\n\ntype InternalListResourceEntry =\n | McpResourceEntry\n | InternalRegistryResourceEntry;\n\nfunction toPublicResourceEntry(\n entry: InternalListResourceEntry,\n): ListResourceEntry {\n if (entry.server === null) {\n const { isDynamic: _isDynamic, ...publicEntry } = entry;\n return publicEntry;\n }\n return entry;\n}\n\n/**\n * Type guard for narrowing a `ListResourceEntry` to an MCP-backed resource.\n * @param entry - The resource entry to check\n * @returns True if the entry is from an MCP server, false if it's from the registry\n */\nexport function isMcpResourceEntry(\n entry: ListResourceEntry,\n): entry is McpResourceEntry {\n return entry.server !== null && isConnectedMcpServer(entry.server);\n}\n\n/**\n * Hook to get the prompts for all the registered MCP servers.\n * @param search - Optional search string to filter prompts by name (case-insensitive).\n * @returns The prompts for the MCP servers, including the server that the prompt was found on.\n */\nexport function useTamboMcpPromptList(search?: string) {\n const mcpServers = useTamboMcpServers();\n\n const queries = useTamboQueries({\n queries: mcpServers.map((mcpServer) => ({\n // search is NOT in queryKey - we filter locally after fetching\n queryKey: [\"mcp-prompts\", mcpServer.key],\n // Only run for connected servers that have a client\n enabled: isConnectedMcpServer(mcpServer),\n queryFn: async (): Promise<ListPromptEntry[]> => {\n // Fast path: if this server doesn't have a client, skip work\n if (!isConnectedMcpServer(mcpServer)) return [];\n\n // Skip if server doesn't support prompts capability\n if (!serverSupportsPrompts(mcpServer)) return [];\n\n try {\n const result = await mcpServer.client.client.listPrompts();\n const prompts: ListPromptItem[] = result?.prompts ?? [];\n // Return prompts without prefixes - we'll apply prefixing in combine\n const promptsEntries = prompts.map((prompt) => ({\n server: mcpServer,\n prompt,\n }));\n return promptsEntries;\n } catch (error) {\n // Gracefully handle MethodNotFound - server doesn't support this method\n if (isMethodNotFoundError(error)) return [];\n throw error;\n }\n },\n })),\n combine: (results) => {\n const combined = combineArrayResults(results);\n\n // Always apply serverKey prefix to MCP prompts (breaking change for consistency with resources)\n // This ensures clear separation between local and remote prompts\n return {\n ...combined,\n data: combined.data.map((entry) => ({\n ...entry,\n prompt: {\n ...entry.prompt,\n name: `${entry.server.serverKey}:${entry.prompt.name}`,\n },\n })),\n };\n },\n });\n\n // Filter results by search string - runs on every search change (not just query completion)\n const filteredData = React.useMemo(() => {\n if (!search) return queries.data;\n\n const normalizedSearch = search.toLowerCase();\n return queries.data.filter((entry) => {\n const name = entry.prompt.name?.toLowerCase() ?? \"\";\n return name.includes(normalizedSearch);\n });\n }, [queries.data, search]);\n\n return {\n ...queries,\n data: filteredData,\n };\n}\n// TODO: find a more general place for this\nfunction combineArrayResults<T>(results: UseQueryResult<T[]>[]): {\n data: T[];\n error: Error | null;\n errors: Error[];\n isPending: boolean;\n isSuccess: boolean;\n isError: boolean;\n isPaused: boolean;\n isRefetching: boolean;\n isFetching: boolean;\n isLoading: boolean;\n refetch: () => Promise<void>;\n} {\n const errors = results\n .filter((result) => result.isError)\n .map((result) => result.error);\n\n // Treat queries that are idle (disabled) as non-blocking for aggregate status\n const enabledish = results.filter(\n (r) => r.fetchStatus !== \"idle\" || r.isSuccess || r.isError,\n );\n\n return {\n // Prefer flatMap to avoid extra intermediate arrays\n data: results.flatMap((result) =>\n result.isSuccess && Array.isArray(result.data) ? result.data : [],\n ),\n // Preserve a single error for compatibility and expose the full list for diagnostics\n error: errors[0] ?? null,\n errors,\n isPending: enabledish.some((result) => result.isPending),\n isSuccess:\n enabledish.length > 0 && enabledish.every((result) => result.isSuccess),\n isError: errors.length > 0,\n isPaused: enabledish.some((result) => result.isPaused),\n isRefetching: enabledish.some((result) => result.isRefetching),\n isFetching: enabledish.some((result) => result.isFetching),\n isLoading: enabledish.some((result) => result.isLoading),\n // Aggregate refetch to trigger all underlying queries\n refetch: async () => {\n await Promise.all(\n results.map(async (r) => {\n await r.refetch();\n }),\n );\n },\n };\n}\n\n/**\n * Type guard for narrowing McpServer to ConnectedMcpServer.\n * A connected server has a non-null client.\n * @param server - The MCP server to check\n * @returns True if the server is connected, false otherwise\n */\nexport function isConnectedMcpServer(\n server: McpServer,\n): server is ConnectedMcpServer {\n return \"client\" in server && server.client != null;\n}\n\n/**\n * Hook to get the prompt for the specified name.\n * @param promptName - The name of the prompt to get. Can be prefixed with serverKey (e.g., \"linear:issue\") or unprefixed.\n * @param args - The arguments to pass to the prompt.\n * @returns The prompt for the specified name.\n */\nexport function useTamboMcpPrompt(\n promptName: string | undefined,\n args: Record<string, string> = {},\n) {\n // figure out which server has the prompt\n const { data: promptEntries } = useTamboMcpPromptList();\n const promptEntry = promptEntries?.find(\n (prompt) => prompt.prompt.name === promptName,\n );\n // Use the stable server key (and the server instance itself) instead of brittle\n // name/url/transport matching.\n const mcpServer = promptEntry?.server;\n\n // Strip the prefix to get the original prompt name for the MCP server call\n const originalPromptName = promptName?.includes(\":\")\n ? promptName.split(\":\").slice(1).join(\":\")\n : promptName;\n\n // Canonicalize args to avoid unstable cache keys from object identity/order\n const sortedArgsEntries = Object.keys(args)\n .sort()\n .map((k) => [k, args[k]] as const);\n return useTamboQuery({\n // Include server identity and sorted args to prevent stale cache hits\n queryKey: [\"mcp-prompt\", promptName, mcpServer?.key, sortedArgsEntries],\n // Only run when we have a prompt name and a connected server\n enabled: Boolean(\n promptName && mcpServer && isConnectedMcpServer(mcpServer),\n ),\n queryFn: async (): Promise<GetPromptResult | null> => {\n if (\n !originalPromptName ||\n !mcpServer ||\n !isConnectedMcpServer(mcpServer)\n ) {\n return null;\n }\n const result = await mcpServer.client.client.getPrompt({\n name: originalPromptName,\n arguments: args,\n });\n return result ?? null; // return null because react-query doesn't like undefined results\n },\n });\n}\n\n/**\n * Hook to get the resources for all the registered MCP servers and registry.\n * @param search - Optional search string. For MCP servers, results are filtered locally after fetching.\n * For registry dynamic sources, the search is passed to listResources(search) for dynamic generation.\n * @returns The resources from MCP servers and the local registry, including the server that the resource was found on (null for registry resources).\n */\nexport function useTamboMcpResourceList(search?: string) {\n const mcpServers = useTamboMcpServers();\n const { resources: staticResources, resourceSource } = useTamboRegistry();\n\n // Build list of queries: MCP servers + optional dynamic resource source\n const queriesToRun = [\n // MCP server queries - search is NOT in queryKey so queries don't re-run on search change\n ...mcpServers.map((mcpServer) => ({\n queryKey: [\"mcp-resources\", mcpServer.key],\n // Only run for connected servers that have a client\n enabled: isConnectedMcpServer(mcpServer),\n queryFn: async (): Promise<McpResourceEntry[]> => {\n // Fast path: if this server doesn't have a client, skip work\n if (!isConnectedMcpServer(mcpServer)) return [];\n\n // Skip if server doesn't support resources capability\n if (!serverSupportsResources(mcpServer)) return [];\n\n try {\n const result = await mcpServer.client.client.listResources();\n const resources: ListResourceItem[] = result?.resources ?? [];\n // Return resources without prefixes - we'll apply prefixing in combine\n const resourceEntries: McpResourceEntry[] = resources.map(\n (resource) => ({\n server: mcpServer,\n resource,\n }),\n );\n return resourceEntries;\n } catch (error) {\n // Gracefully handle MethodNotFound - server doesn't support this method\n if (isMethodNotFoundError(error)) return [];\n throw error;\n }\n },\n })),\n // Dynamic resource source query (if exists) - search IS in queryKey to allow dynamic generation\n ...(resourceSource\n ? [\n {\n queryKey: [\"registry-resources\", \"dynamic\", search],\n enabled: true,\n queryFn: async (): Promise<InternalRegistryResourceEntry[]> => {\n if (!resourceSource) return [];\n const resources = await resourceSource.listResources(search);\n return resources.map((resource) => ({\n server: null,\n resource,\n isDynamic: true,\n }));\n },\n },\n ]\n : []),\n ];\n\n const queries = useTamboQueries({\n queries: queriesToRun,\n combine: (results) => {\n // Type assertion needed because queries can return different entry types\n const combined = combineArrayResults(\n results as UseQueryResult<InternalListResourceEntry[]>[],\n );\n\n // Add static registry resources (no query needed)\n const staticEntries: InternalRegistryResourceEntry[] =\n staticResources.map((resource) => ({\n server: null,\n resource,\n isDynamic: false,\n }));\n\n // Merge static resources with query results (registry resources first)\n const allData = [...staticEntries, ...combined.data];\n\n // Apply serverKey prefix to ALL resources for unified @serverKey:uri format\n // Registry resources get REGISTRY_SERVER_KEY prefix, MCP resources get their serverKey\n const prefixedData = allData.map((entry) => {\n if (entry.server === null) {\n // Registry resource - prefix with REGISTRY_SERVER_KEY\n return {\n ...entry,\n resource: {\n ...entry.resource,\n uri: `${REGISTRY_SERVER_KEY}:${entry.resource.uri}`,\n },\n };\n }\n // MCP resource - always prefix with serverKey\n return {\n ...entry,\n resource: {\n ...entry.resource,\n uri: `${entry.server.serverKey}:${entry.resource.uri}`,\n },\n };\n });\n\n return {\n ...combined,\n data: prefixedData,\n };\n },\n });\n\n // Filter results by search string - runs on every search change (not just query completion)\n // - MCP resources are filtered locally\n // - Static registry resources are filtered locally\n // - Dynamic registry resources are already filtered by listResources(search)\n const filteredData = React.useMemo((): InternalListResourceEntry[] => {\n if (!search) return queries.data;\n\n const normalizedSearch = search.toLowerCase();\n return queries.data.filter((entry) => {\n if (entry.server === null && entry.isDynamic) {\n return true;\n }\n\n const name = entry.resource.name?.toLowerCase() ?? \"\";\n const uri = entry.resource.uri.toLowerCase();\n return name.includes(normalizedSearch) || uri.includes(normalizedSearch);\n });\n }, [queries.data, search]);\n\n const publicData = React.useMemo(\n () => filteredData.map(toPublicResourceEntry),\n [filteredData],\n );\n\n return {\n ...queries,\n data: publicData,\n };\n}\n\n/**\n * Hook to get the resource for the specified URI.\n * @param resourceUri - The URI of the resource to get. Must be prefixed:\n * - MCP resources: prefixed with serverKey (e.g., \"linear:file://foo\")\n * - Registry resources: prefixed with \"registry:\" (e.g., \"registry:file://bar\")\n * @returns The resource for the specified URI.\n */\nexport function useTamboMcpResource(resourceUri: string | undefined) {\n const { resourceSource } = useTamboRegistry();\n const { data: resourceEntries } = useTamboMcpResourceList();\n\n // Find which server/source has the resource\n const resourceEntry = resourceEntries?.find(\n (entry) => entry.resource.uri === resourceUri,\n );\n\n // Determine if this is a registry resource or MCP resource\n const isRegistryResource = resourceEntry?.server === null;\n const mcpServer = resourceEntry?.server ?? null;\n\n // Check if the URI has the registry prefix\n const hasRegistryPrefix = Boolean(\n resourceUri?.startsWith(`${REGISTRY_SERVER_KEY}:`),\n );\n\n // Strip the prefix to get the original resource URI for fetching\n let originalResourceUri: string | undefined;\n if (isRegistryResource || hasRegistryPrefix) {\n const prefixLen = REGISTRY_SERVER_KEY.length + 1; // +1 for the colon\n originalResourceUri = resourceUri?.slice(prefixLen);\n } else if (mcpServer) {\n const prefixLen = mcpServer.serverKey.length + 1; // +1 for the colon\n originalResourceUri = resourceUri?.slice(prefixLen);\n }\n\n // Check if we can fetch this resource\n const hasRegistrySource = resourceSource != null;\n const hasConnectedMcpServer =\n mcpServer != null && isConnectedMcpServer(mcpServer);\n const canFetchFromRegistry =\n hasRegistrySource && (isRegistryResource || hasRegistryPrefix);\n const canFetchResource = Boolean(\n resourceUri && (canFetchFromRegistry || hasConnectedMcpServer),\n );\n\n const locationKey =\n isRegistryResource || hasRegistryPrefix\n ? REGISTRY_SERVER_KEY\n : mcpServer?.key;\n\n return useTamboQuery({\n queryKey: [\"resource\", resourceUri, locationKey],\n enabled: canFetchResource,\n queryFn: async (): Promise<ReadResourceResult | null> => {\n if (!originalResourceUri) {\n return null;\n }\n\n // Registry resource: use resourceSource.getResource\n if (resourceSource && (isRegistryResource || hasRegistryPrefix)) {\n const result = await resourceSource.getResource(originalResourceUri);\n return result ?? null;\n }\n\n // MCP resource: use MCP client\n if (mcpServer && isConnectedMcpServer(mcpServer)) {\n const result = await mcpServer.client.client.readResource({\n uri: originalResourceUri,\n });\n return result ?? null;\n }\n\n return null;\n },\n });\n}\n"]}