@tambo-ai/react 0.70.0 → 0.71.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 (257) hide show
  1. package/dist/v1/hooks/use-tambo-v1-messages.d.ts +58 -0
  2. package/dist/v1/hooks/use-tambo-v1-messages.d.ts.map +1 -0
  3. package/dist/v1/hooks/use-tambo-v1-messages.js +54 -0
  4. package/dist/v1/hooks/use-tambo-v1-messages.js.map +1 -0
  5. package/dist/v1/hooks/use-tambo-v1-messages.test.d.ts +2 -0
  6. package/dist/v1/hooks/use-tambo-v1-messages.test.d.ts.map +1 -0
  7. package/dist/v1/hooks/use-tambo-v1-messages.test.js +137 -0
  8. package/dist/v1/hooks/use-tambo-v1-messages.test.js.map +1 -0
  9. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts +96 -0
  10. package/dist/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -0
  11. package/dist/v1/hooks/use-tambo-v1-send-message.js +227 -0
  12. package/dist/v1/hooks/use-tambo-v1-send-message.js.map +1 -0
  13. package/dist/v1/hooks/use-tambo-v1-send-message.test.d.ts +2 -0
  14. package/dist/v1/hooks/use-tambo-v1-send-message.test.d.ts.map +1 -0
  15. package/dist/v1/hooks/use-tambo-v1-send-message.test.js +827 -0
  16. package/dist/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -0
  17. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts +61 -0
  18. package/dist/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -0
  19. package/dist/v1/hooks/use-tambo-v1-thread-list.js +56 -0
  20. package/dist/v1/hooks/use-tambo-v1-thread-list.js.map +1 -0
  21. package/dist/v1/hooks/use-tambo-v1-thread-list.test.d.ts +2 -0
  22. package/dist/v1/hooks/use-tambo-v1-thread-list.test.d.ts.map +1 -0
  23. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js +98 -0
  24. package/dist/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -0
  25. package/dist/v1/hooks/use-tambo-v1-thread.d.ts +37 -0
  26. package/dist/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -0
  27. package/dist/v1/hooks/use-tambo-v1-thread.js +49 -0
  28. package/dist/v1/hooks/use-tambo-v1-thread.js.map +1 -0
  29. package/dist/v1/hooks/use-tambo-v1-thread.test.d.ts +2 -0
  30. package/dist/v1/hooks/use-tambo-v1-thread.test.d.ts.map +1 -0
  31. package/dist/v1/hooks/use-tambo-v1-thread.test.js +83 -0
  32. package/dist/v1/hooks/use-tambo-v1-thread.test.js.map +1 -0
  33. package/dist/v1/hooks/use-tambo-v1.d.ts +107 -0
  34. package/dist/v1/hooks/use-tambo-v1.d.ts.map +1 -0
  35. package/dist/v1/hooks/use-tambo-v1.js +87 -0
  36. package/dist/v1/hooks/use-tambo-v1.js.map +1 -0
  37. package/dist/v1/hooks/use-tambo-v1.test.d.ts +2 -0
  38. package/dist/v1/hooks/use-tambo-v1.test.d.ts.map +1 -0
  39. package/dist/v1/hooks/use-tambo-v1.test.js +150 -0
  40. package/dist/v1/hooks/use-tambo-v1.test.js.map +1 -0
  41. package/dist/v1/index.d.ts +54 -16
  42. package/dist/v1/index.d.ts.map +1 -1
  43. package/dist/v1/index.js +85 -26
  44. package/dist/v1/index.js.map +1 -1
  45. package/dist/v1/providers/tambo-v1-provider.d.ts +91 -0
  46. package/dist/v1/providers/tambo-v1-provider.d.ts.map +1 -0
  47. package/dist/v1/providers/tambo-v1-provider.js +110 -0
  48. package/dist/v1/providers/tambo-v1-provider.js.map +1 -0
  49. package/dist/v1/providers/tambo-v1-provider.test.d.ts +2 -0
  50. package/dist/v1/providers/tambo-v1-provider.test.d.ts.map +1 -0
  51. package/dist/v1/providers/tambo-v1-provider.test.js +123 -0
  52. package/dist/v1/providers/tambo-v1-provider.test.js.map +1 -0
  53. package/dist/v1/providers/tambo-v1-stream-context.d.ts +136 -0
  54. package/dist/v1/providers/tambo-v1-stream-context.d.ts.map +1 -0
  55. package/dist/v1/providers/tambo-v1-stream-context.js +230 -0
  56. package/dist/v1/providers/tambo-v1-stream-context.js.map +1 -0
  57. package/dist/v1/providers/tambo-v1-stream-context.test.d.ts +2 -0
  58. package/dist/v1/providers/tambo-v1-stream-context.test.d.ts.map +1 -0
  59. package/dist/v1/providers/tambo-v1-stream-context.test.js +85 -0
  60. package/dist/v1/providers/tambo-v1-stream-context.test.js.map +1 -0
  61. package/dist/v1/types/component.d.ts +5 -2
  62. package/dist/v1/types/component.d.ts.map +1 -1
  63. package/dist/v1/types/component.js +5 -2
  64. package/dist/v1/types/component.js.map +1 -1
  65. package/dist/v1/types/event.d.ts +21 -12
  66. package/dist/v1/types/event.d.ts.map +1 -1
  67. package/dist/v1/types/event.js +46 -1
  68. package/dist/v1/types/event.js.map +1 -1
  69. package/dist/v1/types/event.test.d.ts +2 -0
  70. package/dist/v1/types/event.test.d.ts.map +1 -0
  71. package/dist/v1/types/event.test.js +70 -0
  72. package/dist/v1/types/event.test.js.map +1 -0
  73. package/dist/v1/types/message.d.ts +4 -8
  74. package/dist/v1/types/message.d.ts.map +1 -1
  75. package/dist/v1/types/message.js +1 -1
  76. package/dist/v1/types/message.js.map +1 -1
  77. package/dist/v1/types/thread.d.ts +1 -3
  78. package/dist/v1/types/thread.d.ts.map +1 -1
  79. package/dist/v1/types/thread.js +1 -1
  80. package/dist/v1/types/thread.js.map +1 -1
  81. package/dist/v1/utils/event-accumulator.d.ts +100 -0
  82. package/dist/v1/utils/event-accumulator.d.ts.map +1 -0
  83. package/dist/v1/utils/event-accumulator.js +715 -0
  84. package/dist/v1/utils/event-accumulator.js.map +1 -0
  85. package/dist/v1/utils/event-accumulator.test.d.ts +2 -0
  86. package/dist/v1/utils/event-accumulator.test.d.ts.map +1 -0
  87. package/dist/v1/utils/event-accumulator.test.js +1010 -0
  88. package/dist/v1/utils/event-accumulator.test.js.map +1 -0
  89. package/dist/v1/utils/json-patch.d.ts +18 -0
  90. package/dist/v1/utils/json-patch.d.ts.map +1 -0
  91. package/dist/v1/utils/json-patch.js +35 -0
  92. package/dist/v1/utils/json-patch.js.map +1 -0
  93. package/dist/v1/utils/json-patch.test.d.ts +2 -0
  94. package/dist/v1/utils/json-patch.test.d.ts.map +1 -0
  95. package/dist/v1/utils/json-patch.test.js +28 -0
  96. package/dist/v1/utils/json-patch.test.js.map +1 -0
  97. package/dist/v1/utils/registry-conversion.d.ts +53 -0
  98. package/dist/v1/utils/registry-conversion.d.ts.map +1 -0
  99. package/dist/v1/utils/registry-conversion.js +114 -0
  100. package/dist/v1/utils/registry-conversion.js.map +1 -0
  101. package/dist/v1/utils/registry-conversion.test.d.ts +2 -0
  102. package/dist/v1/utils/registry-conversion.test.d.ts.map +1 -0
  103. package/dist/v1/utils/registry-conversion.test.js +179 -0
  104. package/dist/v1/utils/registry-conversion.test.js.map +1 -0
  105. package/dist/v1/utils/stream-handler.d.ts +45 -0
  106. package/dist/v1/utils/stream-handler.d.ts.map +1 -0
  107. package/dist/v1/utils/stream-handler.js +47 -0
  108. package/dist/v1/utils/stream-handler.js.map +1 -0
  109. package/dist/v1/utils/stream-handler.test.d.ts +2 -0
  110. package/dist/v1/utils/stream-handler.test.d.ts.map +1 -0
  111. package/dist/v1/utils/stream-handler.test.js +74 -0
  112. package/dist/v1/utils/stream-handler.test.js.map +1 -0
  113. package/dist/v1/utils/tool-call-tracker.d.ts +41 -0
  114. package/dist/v1/utils/tool-call-tracker.d.ts.map +1 -0
  115. package/dist/v1/utils/tool-call-tracker.js +90 -0
  116. package/dist/v1/utils/tool-call-tracker.js.map +1 -0
  117. package/dist/v1/utils/tool-executor.d.ts +33 -0
  118. package/dist/v1/utils/tool-executor.d.ts.map +1 -0
  119. package/dist/v1/utils/tool-executor.js +103 -0
  120. package/dist/v1/utils/tool-executor.js.map +1 -0
  121. package/dist/v1/utils/tool-executor.test.d.ts +2 -0
  122. package/dist/v1/utils/tool-executor.test.d.ts.map +1 -0
  123. package/dist/v1/utils/tool-executor.test.js +222 -0
  124. package/dist/v1/utils/tool-executor.test.js.map +1 -0
  125. package/esm/v1/hooks/use-tambo-v1-messages.d.ts +58 -0
  126. package/esm/v1/hooks/use-tambo-v1-messages.d.ts.map +1 -0
  127. package/esm/v1/hooks/use-tambo-v1-messages.js +51 -0
  128. package/esm/v1/hooks/use-tambo-v1-messages.js.map +1 -0
  129. package/esm/v1/hooks/use-tambo-v1-messages.test.d.ts +2 -0
  130. package/esm/v1/hooks/use-tambo-v1-messages.test.d.ts.map +1 -0
  131. package/esm/v1/hooks/use-tambo-v1-messages.test.js +132 -0
  132. package/esm/v1/hooks/use-tambo-v1-messages.test.js.map +1 -0
  133. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts +96 -0
  134. package/esm/v1/hooks/use-tambo-v1-send-message.d.ts.map +1 -0
  135. package/esm/v1/hooks/use-tambo-v1-send-message.js +223 -0
  136. package/esm/v1/hooks/use-tambo-v1-send-message.js.map +1 -0
  137. package/esm/v1/hooks/use-tambo-v1-send-message.test.d.ts +2 -0
  138. package/esm/v1/hooks/use-tambo-v1-send-message.test.d.ts.map +1 -0
  139. package/esm/v1/hooks/use-tambo-v1-send-message.test.js +822 -0
  140. package/esm/v1/hooks/use-tambo-v1-send-message.test.js.map +1 -0
  141. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts +61 -0
  142. package/esm/v1/hooks/use-tambo-v1-thread-list.d.ts.map +1 -0
  143. package/esm/v1/hooks/use-tambo-v1-thread-list.js +53 -0
  144. package/esm/v1/hooks/use-tambo-v1-thread-list.js.map +1 -0
  145. package/esm/v1/hooks/use-tambo-v1-thread-list.test.d.ts +2 -0
  146. package/esm/v1/hooks/use-tambo-v1-thread-list.test.d.ts.map +1 -0
  147. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js +93 -0
  148. package/esm/v1/hooks/use-tambo-v1-thread-list.test.js.map +1 -0
  149. package/esm/v1/hooks/use-tambo-v1-thread.d.ts +37 -0
  150. package/esm/v1/hooks/use-tambo-v1-thread.d.ts.map +1 -0
  151. package/esm/v1/hooks/use-tambo-v1-thread.js +46 -0
  152. package/esm/v1/hooks/use-tambo-v1-thread.js.map +1 -0
  153. package/esm/v1/hooks/use-tambo-v1-thread.test.d.ts +2 -0
  154. package/esm/v1/hooks/use-tambo-v1-thread.test.d.ts.map +1 -0
  155. package/esm/v1/hooks/use-tambo-v1-thread.test.js +78 -0
  156. package/esm/v1/hooks/use-tambo-v1-thread.test.js.map +1 -0
  157. package/esm/v1/hooks/use-tambo-v1.d.ts +107 -0
  158. package/esm/v1/hooks/use-tambo-v1.d.ts.map +1 -0
  159. package/esm/v1/hooks/use-tambo-v1.js +84 -0
  160. package/esm/v1/hooks/use-tambo-v1.js.map +1 -0
  161. package/esm/v1/hooks/use-tambo-v1.test.d.ts +2 -0
  162. package/esm/v1/hooks/use-tambo-v1.test.d.ts.map +1 -0
  163. package/esm/v1/hooks/use-tambo-v1.test.js +145 -0
  164. package/esm/v1/hooks/use-tambo-v1.test.js.map +1 -0
  165. package/esm/v1/index.d.ts +54 -16
  166. package/esm/v1/index.d.ts.map +1 -1
  167. package/esm/v1/index.js +64 -27
  168. package/esm/v1/index.js.map +1 -1
  169. package/esm/v1/providers/tambo-v1-provider.d.ts +91 -0
  170. package/esm/v1/providers/tambo-v1-provider.d.ts.map +1 -0
  171. package/esm/v1/providers/tambo-v1-provider.js +74 -0
  172. package/esm/v1/providers/tambo-v1-provider.js.map +1 -0
  173. package/esm/v1/providers/tambo-v1-provider.test.d.ts +2 -0
  174. package/esm/v1/providers/tambo-v1-provider.test.d.ts.map +1 -0
  175. package/esm/v1/providers/tambo-v1-provider.test.js +118 -0
  176. package/esm/v1/providers/tambo-v1-provider.test.js.map +1 -0
  177. package/esm/v1/providers/tambo-v1-stream-context.d.ts +136 -0
  178. package/esm/v1/providers/tambo-v1-stream-context.d.ts.map +1 -0
  179. package/esm/v1/providers/tambo-v1-stream-context.js +191 -0
  180. package/esm/v1/providers/tambo-v1-stream-context.js.map +1 -0
  181. package/esm/v1/providers/tambo-v1-stream-context.test.d.ts +2 -0
  182. package/esm/v1/providers/tambo-v1-stream-context.test.d.ts.map +1 -0
  183. package/esm/v1/providers/tambo-v1-stream-context.test.js +80 -0
  184. package/esm/v1/providers/tambo-v1-stream-context.test.js.map +1 -0
  185. package/esm/v1/types/component.d.ts +5 -2
  186. package/esm/v1/types/component.d.ts.map +1 -1
  187. package/esm/v1/types/component.js +5 -2
  188. package/esm/v1/types/component.js.map +1 -1
  189. package/esm/v1/types/event.d.ts +21 -12
  190. package/esm/v1/types/event.d.ts.map +1 -1
  191. package/esm/v1/types/event.js +44 -2
  192. package/esm/v1/types/event.js.map +1 -1
  193. package/esm/v1/types/event.test.d.ts +2 -0
  194. package/esm/v1/types/event.test.d.ts.map +1 -0
  195. package/esm/v1/types/event.test.js +68 -0
  196. package/esm/v1/types/event.test.js.map +1 -0
  197. package/esm/v1/types/message.d.ts +4 -8
  198. package/esm/v1/types/message.d.ts.map +1 -1
  199. package/esm/v1/types/message.js +1 -1
  200. package/esm/v1/types/message.js.map +1 -1
  201. package/esm/v1/types/thread.d.ts +1 -3
  202. package/esm/v1/types/thread.d.ts.map +1 -1
  203. package/esm/v1/types/thread.js +1 -1
  204. package/esm/v1/types/thread.js.map +1 -1
  205. package/esm/v1/utils/event-accumulator.d.ts +100 -0
  206. package/esm/v1/utils/event-accumulator.d.ts.map +1 -0
  207. package/esm/v1/utils/event-accumulator.js +708 -0
  208. package/esm/v1/utils/event-accumulator.js.map +1 -0
  209. package/esm/v1/utils/event-accumulator.test.d.ts +2 -0
  210. package/esm/v1/utils/event-accumulator.test.d.ts.map +1 -0
  211. package/esm/v1/utils/event-accumulator.test.js +1008 -0
  212. package/esm/v1/utils/event-accumulator.test.js.map +1 -0
  213. package/esm/v1/utils/json-patch.d.ts +18 -0
  214. package/esm/v1/utils/json-patch.d.ts.map +1 -0
  215. package/esm/v1/utils/json-patch.js +32 -0
  216. package/esm/v1/utils/json-patch.js.map +1 -0
  217. package/esm/v1/utils/json-patch.test.d.ts +2 -0
  218. package/esm/v1/utils/json-patch.test.d.ts.map +1 -0
  219. package/esm/v1/utils/json-patch.test.js +26 -0
  220. package/esm/v1/utils/json-patch.test.js.map +1 -0
  221. package/esm/v1/utils/registry-conversion.d.ts +53 -0
  222. package/esm/v1/utils/registry-conversion.d.ts.map +1 -0
  223. package/esm/v1/utils/registry-conversion.js +108 -0
  224. package/esm/v1/utils/registry-conversion.js.map +1 -0
  225. package/esm/v1/utils/registry-conversion.test.d.ts +2 -0
  226. package/esm/v1/utils/registry-conversion.test.d.ts.map +1 -0
  227. package/esm/v1/utils/registry-conversion.test.js +177 -0
  228. package/esm/v1/utils/registry-conversion.test.js.map +1 -0
  229. package/esm/v1/utils/stream-handler.d.ts +45 -0
  230. package/esm/v1/utils/stream-handler.d.ts.map +1 -0
  231. package/esm/v1/utils/stream-handler.js +44 -0
  232. package/esm/v1/utils/stream-handler.js.map +1 -0
  233. package/esm/v1/utils/stream-handler.test.d.ts +2 -0
  234. package/esm/v1/utils/stream-handler.test.d.ts.map +1 -0
  235. package/esm/v1/utils/stream-handler.test.js +72 -0
  236. package/esm/v1/utils/stream-handler.test.js.map +1 -0
  237. package/esm/v1/utils/tool-call-tracker.d.ts +41 -0
  238. package/esm/v1/utils/tool-call-tracker.d.ts.map +1 -0
  239. package/esm/v1/utils/tool-call-tracker.js +86 -0
  240. package/esm/v1/utils/tool-call-tracker.js.map +1 -0
  241. package/esm/v1/utils/tool-executor.d.ts +33 -0
  242. package/esm/v1/utils/tool-executor.d.ts.map +1 -0
  243. package/esm/v1/utils/tool-executor.js +99 -0
  244. package/esm/v1/utils/tool-executor.js.map +1 -0
  245. package/esm/v1/utils/tool-executor.test.d.ts +2 -0
  246. package/esm/v1/utils/tool-executor.test.d.ts.map +1 -0
  247. package/esm/v1/utils/tool-executor.test.js +220 -0
  248. package/esm/v1/utils/tool-executor.test.js.map +1 -0
  249. package/package.json +7 -6
  250. package/dist/v1/types/tool.d.ts +0 -52
  251. package/dist/v1/types/tool.d.ts.map +0 -1
  252. package/dist/v1/types/tool.js +0 -11
  253. package/dist/v1/types/tool.js.map +0 -1
  254. package/esm/v1/types/tool.d.ts +0 -52
  255. package/esm/v1/types/tool.d.ts.map +0 -1
  256. package/esm/v1/types/tool.js +0 -10
  257. package/esm/v1/types/tool.js.map +0 -1
@@ -0,0 +1,827 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const core_1 = require("@ag-ui/core");
7
+ const react_query_1 = require("@tanstack/react-query");
8
+ const react_1 = require("@testing-library/react");
9
+ const react_2 = __importDefault(require("react"));
10
+ const zod_1 = require("zod");
11
+ const tambo_client_provider_1 = require("../../providers/tambo-client-provider");
12
+ const tambo_registry_provider_1 = require("../../providers/tambo-registry-provider");
13
+ const tambo_v1_stream_context_1 = require("../providers/tambo-v1-stream-context");
14
+ const use_tambo_v1_send_message_1 = require("./use-tambo-v1-send-message");
15
+ jest.mock("../../providers/tambo-client-provider", () => ({
16
+ useTamboClient: jest.fn(),
17
+ }));
18
+ describe("useTamboV1SendMessage", () => {
19
+ const mockThreadsRunsApi = {
20
+ run: jest.fn(),
21
+ create: jest.fn(),
22
+ };
23
+ const mockTamboAI = {
24
+ apiKey: "",
25
+ threads: {
26
+ runs: mockThreadsRunsApi,
27
+ },
28
+ };
29
+ const mockRegistry = {
30
+ componentList: new Map(),
31
+ toolRegistry: new Map(),
32
+ };
33
+ let queryClient;
34
+ function TestWrapper({ children }) {
35
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
36
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
37
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
38
+ }
39
+ beforeEach(() => {
40
+ queryClient = new react_query_1.QueryClient({
41
+ defaultOptions: {
42
+ queries: { retry: false },
43
+ mutations: { retry: false },
44
+ },
45
+ });
46
+ jest.mocked(tambo_client_provider_1.useTamboClient).mockReturnValue(mockTamboAI);
47
+ mockThreadsRunsApi.run.mockReset();
48
+ mockThreadsRunsApi.create.mockReset();
49
+ });
50
+ it("returns a mutation object", () => {
51
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
52
+ wrapper: TestWrapper,
53
+ });
54
+ expect(result.current.mutate).toBeDefined();
55
+ expect(result.current.mutateAsync).toBeDefined();
56
+ expect(result.current.isPending).toBe(false);
57
+ });
58
+ it("returns a mutation object when threadId is not provided", () => {
59
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)(), {
60
+ wrapper: TestWrapper,
61
+ });
62
+ expect(result.current.mutate).toBeDefined();
63
+ expect(result.current.mutateAsync).toBeDefined();
64
+ });
65
+ });
66
+ describe("createRunStream", () => {
67
+ const mockStream = {
68
+ [Symbol.asyncIterator]: async function* () {
69
+ yield { type: "RUN_STARTED", runId: "run_1", threadId: "thread_123" };
70
+ },
71
+ };
72
+ const mockThreadsRunsApi = {
73
+ run: jest.fn(),
74
+ create: jest.fn(),
75
+ };
76
+ const mockClient = {
77
+ threads: {
78
+ runs: mockThreadsRunsApi,
79
+ },
80
+ };
81
+ const mockRegistry = {
82
+ componentList: new Map([
83
+ [
84
+ "TestComponent",
85
+ {
86
+ name: "TestComponent",
87
+ description: "A test component",
88
+ component: () => null,
89
+ propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
90
+ },
91
+ ],
92
+ ]),
93
+ toolRegistry: new Map([
94
+ [
95
+ "testTool",
96
+ {
97
+ name: "testTool",
98
+ description: "A test tool",
99
+ tool: async () => "result",
100
+ inputSchema: zod_1.z.object({ query: zod_1.z.string() }),
101
+ },
102
+ ],
103
+ ]),
104
+ };
105
+ const testMessage = {
106
+ role: "user",
107
+ content: [{ type: "text", text: "Hello" }],
108
+ };
109
+ beforeEach(() => {
110
+ mockThreadsRunsApi.run.mockReset();
111
+ mockThreadsRunsApi.create.mockReset();
112
+ });
113
+ it("calls client.threads.runs.run when threadId is provided", async () => {
114
+ mockThreadsRunsApi.run.mockResolvedValue(mockStream);
115
+ const result = await (0, use_tambo_v1_send_message_1.createRunStream)({
116
+ client: mockClient,
117
+ threadId: "thread_123",
118
+ message: testMessage,
119
+ registry: mockRegistry,
120
+ });
121
+ expect(mockThreadsRunsApi.run).toHaveBeenCalledWith("thread_123", {
122
+ message: testMessage,
123
+ availableComponents: expect.any(Array),
124
+ tools: expect.any(Array),
125
+ });
126
+ expect(mockThreadsRunsApi.create).not.toHaveBeenCalled();
127
+ expect(result.stream).toBe(mockStream);
128
+ expect(result.initialThreadId).toBe("thread_123");
129
+ });
130
+ it("calls client.threads.runs.create when threadId is not provided", async () => {
131
+ mockThreadsRunsApi.create.mockResolvedValue(mockStream);
132
+ const result = await (0, use_tambo_v1_send_message_1.createRunStream)({
133
+ client: mockClient,
134
+ threadId: undefined,
135
+ message: testMessage,
136
+ registry: mockRegistry,
137
+ });
138
+ expect(mockThreadsRunsApi.create).toHaveBeenCalledWith({
139
+ message: testMessage,
140
+ availableComponents: expect.any(Array),
141
+ tools: expect.any(Array),
142
+ });
143
+ expect(mockThreadsRunsApi.run).not.toHaveBeenCalled();
144
+ expect(result.stream).toBe(mockStream);
145
+ expect(result.initialThreadId).toBeUndefined();
146
+ });
147
+ it("converts registry components to availableComponents format", async () => {
148
+ mockThreadsRunsApi.run.mockResolvedValue(mockStream);
149
+ await (0, use_tambo_v1_send_message_1.createRunStream)({
150
+ client: mockClient,
151
+ threadId: "thread_123",
152
+ message: testMessage,
153
+ registry: mockRegistry,
154
+ });
155
+ const callArgs = mockThreadsRunsApi.run.mock.calls[0][1];
156
+ expect(callArgs.availableComponents).toEqual([
157
+ {
158
+ name: "TestComponent",
159
+ description: "A test component",
160
+ propsSchema: expect.any(Object),
161
+ },
162
+ ]);
163
+ });
164
+ it("converts registry tools to tools format", async () => {
165
+ mockThreadsRunsApi.run.mockResolvedValue(mockStream);
166
+ await (0, use_tambo_v1_send_message_1.createRunStream)({
167
+ client: mockClient,
168
+ threadId: "thread_123",
169
+ message: testMessage,
170
+ registry: mockRegistry,
171
+ });
172
+ const callArgs = mockThreadsRunsApi.run.mock.calls[0][1];
173
+ expect(callArgs.tools).toEqual([
174
+ expect.objectContaining({
175
+ name: "testTool",
176
+ description: "A test tool",
177
+ }),
178
+ ]);
179
+ });
180
+ it("handles empty registry", async () => {
181
+ mockThreadsRunsApi.run.mockResolvedValue(mockStream);
182
+ const emptyRegistry = {
183
+ componentList: new Map(),
184
+ toolRegistry: new Map(),
185
+ };
186
+ await (0, use_tambo_v1_send_message_1.createRunStream)({
187
+ client: mockClient,
188
+ threadId: "thread_123",
189
+ message: testMessage,
190
+ registry: emptyRegistry,
191
+ });
192
+ const callArgs = mockThreadsRunsApi.run.mock.calls[0][1];
193
+ expect(callArgs.availableComponents).toEqual([]);
194
+ expect(callArgs.tools).toEqual([]);
195
+ });
196
+ });
197
+ describe("useTamboV1SendMessage mutation", () => {
198
+ const mockThreadsRunsApi = {
199
+ run: jest.fn(),
200
+ create: jest.fn(),
201
+ };
202
+ const mockTamboAI = {
203
+ apiKey: "",
204
+ threads: {
205
+ runs: mockThreadsRunsApi,
206
+ },
207
+ };
208
+ let queryClient;
209
+ function createAsyncIterator(events) {
210
+ return {
211
+ [Symbol.asyncIterator]: async function* () {
212
+ for (const event of events) {
213
+ yield event;
214
+ }
215
+ },
216
+ };
217
+ }
218
+ beforeEach(() => {
219
+ queryClient = new react_query_1.QueryClient({
220
+ defaultOptions: {
221
+ queries: { retry: false },
222
+ mutations: { retry: false },
223
+ },
224
+ });
225
+ jest.mocked(tambo_client_provider_1.useTamboClient).mockReturnValue(mockTamboAI);
226
+ mockThreadsRunsApi.run.mockReset();
227
+ mockThreadsRunsApi.create.mockReset();
228
+ });
229
+ it("extracts threadId from RUN_STARTED event when creating new thread", async () => {
230
+ const mockStream = createAsyncIterator([
231
+ {
232
+ type: core_1.EventType.RUN_STARTED,
233
+ runId: "run_1",
234
+ threadId: "new_thread_123",
235
+ },
236
+ { type: core_1.EventType.RUN_FINISHED },
237
+ ]);
238
+ mockThreadsRunsApi.create.mockResolvedValue(mockStream);
239
+ const mockRegistry = {
240
+ componentList: new Map(),
241
+ toolRegistry: new Map(),
242
+ };
243
+ function TestWrapper({ children }) {
244
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
245
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
246
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, null, children))));
247
+ }
248
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)(), {
249
+ wrapper: TestWrapper,
250
+ });
251
+ let mutationResult;
252
+ await (0, react_1.act)(async () => {
253
+ mutationResult = await result.current.mutateAsync({
254
+ message: {
255
+ role: "user",
256
+ content: [{ type: "text", text: "Hello" }],
257
+ },
258
+ });
259
+ });
260
+ expect(mutationResult?.threadId).toBe("new_thread_123");
261
+ });
262
+ it("throws error when first event is not RUN_STARTED on new thread", async () => {
263
+ const mockStream = createAsyncIterator([
264
+ { type: core_1.EventType.TEXT_MESSAGE_START, messageId: "msg_1" },
265
+ ]);
266
+ mockThreadsRunsApi.create.mockResolvedValue(mockStream);
267
+ const mockRegistry = {
268
+ componentList: new Map(),
269
+ toolRegistry: new Map(),
270
+ };
271
+ function TestWrapper({ children }) {
272
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
273
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
274
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, null, children))));
275
+ }
276
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)(), {
277
+ wrapper: TestWrapper,
278
+ });
279
+ await expect((0, react_1.act)(async () => {
280
+ await result.current.mutateAsync({
281
+ message: {
282
+ role: "user",
283
+ content: [{ type: "text", text: "Hello" }],
284
+ },
285
+ });
286
+ })).rejects.toThrow("Expected first event to be RUN_STARTED with threadId");
287
+ });
288
+ it("executes tools on awaiting_input event", async () => {
289
+ const toolExecuted = jest.fn().mockResolvedValue("tool result");
290
+ const testTool = {
291
+ name: "test_tool",
292
+ description: "A test tool",
293
+ tool: toolExecuted,
294
+ inputSchema: zod_1.z.object({ query: zod_1.z.string() }),
295
+ outputSchema: zod_1.z.string(),
296
+ };
297
+ const mockRegistry = {
298
+ componentList: new Map(),
299
+ toolRegistry: new Map([["test_tool", testTool]]),
300
+ };
301
+ const initialStream = createAsyncIterator([
302
+ {
303
+ type: core_1.EventType.RUN_STARTED,
304
+ runId: "run_1",
305
+ threadId: "thread_123",
306
+ },
307
+ {
308
+ type: core_1.EventType.TEXT_MESSAGE_START,
309
+ messageId: "msg_1",
310
+ role: "assistant",
311
+ },
312
+ {
313
+ type: core_1.EventType.TOOL_CALL_START,
314
+ toolCallId: "call_1",
315
+ toolCallName: "test_tool",
316
+ parentMessageId: "msg_1",
317
+ },
318
+ {
319
+ type: core_1.EventType.TOOL_CALL_ARGS,
320
+ toolCallId: "call_1",
321
+ delta: '{"query":"test"}',
322
+ },
323
+ {
324
+ type: core_1.EventType.TOOL_CALL_END,
325
+ toolCallId: "call_1",
326
+ },
327
+ {
328
+ type: core_1.EventType.CUSTOM,
329
+ name: "tambo.run.awaiting_input",
330
+ value: { pendingToolCallIds: ["call_1"] },
331
+ },
332
+ ]);
333
+ const continueStream = createAsyncIterator([
334
+ {
335
+ type: core_1.EventType.RUN_STARTED,
336
+ runId: "run_2",
337
+ threadId: "thread_123",
338
+ },
339
+ { type: core_1.EventType.RUN_FINISHED },
340
+ ]);
341
+ mockThreadsRunsApi.run
342
+ .mockResolvedValueOnce(initialStream)
343
+ .mockResolvedValueOnce(continueStream);
344
+ function TestWrapper({ children }) {
345
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
346
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
347
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
348
+ }
349
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
350
+ wrapper: TestWrapper,
351
+ });
352
+ await (0, react_1.act)(async () => {
353
+ await result.current.mutateAsync({
354
+ message: {
355
+ role: "user",
356
+ content: [{ type: "text", text: "Hello" }],
357
+ },
358
+ });
359
+ });
360
+ expect(toolExecuted).toHaveBeenCalledWith({ query: "test" });
361
+ // Verify continuation was called with tool results
362
+ expect(mockThreadsRunsApi.run).toHaveBeenCalledTimes(2);
363
+ const continueCall = mockThreadsRunsApi.run.mock.calls[1];
364
+ expect(continueCall[0]).toBe("thread_123");
365
+ expect(continueCall[1].previousRunId).toBe("run_1");
366
+ expect(continueCall[1].message.content[0]).toEqual({
367
+ type: "tool_result",
368
+ toolUseId: "call_1",
369
+ content: [{ type: "text", text: "tool result" }],
370
+ });
371
+ });
372
+ it("handles tool calls with chunked args", async () => {
373
+ const toolExecuted = jest.fn().mockResolvedValue({ result: 42 });
374
+ const testTool = {
375
+ name: "chunked_tool",
376
+ description: "Tool with chunked args",
377
+ tool: toolExecuted,
378
+ inputSchema: zod_1.z.object({ a: zod_1.z.number(), b: zod_1.z.number() }),
379
+ outputSchema: zod_1.z.object({ result: zod_1.z.number() }),
380
+ };
381
+ const mockRegistry = {
382
+ componentList: new Map(),
383
+ toolRegistry: new Map([["chunked_tool", testTool]]),
384
+ };
385
+ const initialStream = createAsyncIterator([
386
+ {
387
+ type: core_1.EventType.RUN_STARTED,
388
+ runId: "run_1",
389
+ threadId: "thread_123",
390
+ },
391
+ {
392
+ type: core_1.EventType.TEXT_MESSAGE_START,
393
+ messageId: "msg_1",
394
+ role: "assistant",
395
+ },
396
+ {
397
+ type: core_1.EventType.TOOL_CALL_START,
398
+ toolCallId: "call_1",
399
+ toolCallName: "chunked_tool",
400
+ parentMessageId: "msg_1",
401
+ },
402
+ {
403
+ type: core_1.EventType.TOOL_CALL_ARGS,
404
+ toolCallId: "call_1",
405
+ delta: '{"a":',
406
+ },
407
+ {
408
+ type: core_1.EventType.TOOL_CALL_ARGS,
409
+ toolCallId: "call_1",
410
+ delta: "10,",
411
+ },
412
+ {
413
+ type: core_1.EventType.TOOL_CALL_ARGS,
414
+ toolCallId: "call_1",
415
+ delta: '"b":20}',
416
+ },
417
+ {
418
+ type: core_1.EventType.TOOL_CALL_END,
419
+ toolCallId: "call_1",
420
+ },
421
+ {
422
+ type: core_1.EventType.CUSTOM,
423
+ name: "tambo.run.awaiting_input",
424
+ value: { pendingToolCallIds: ["call_1"] },
425
+ },
426
+ ]);
427
+ const continueStream = createAsyncIterator([
428
+ {
429
+ type: core_1.EventType.RUN_STARTED,
430
+ runId: "run_2",
431
+ threadId: "thread_123",
432
+ },
433
+ { type: core_1.EventType.RUN_FINISHED },
434
+ ]);
435
+ mockThreadsRunsApi.run
436
+ .mockResolvedValueOnce(initialStream)
437
+ .mockResolvedValueOnce(continueStream);
438
+ function TestWrapper({ children }) {
439
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
440
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
441
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
442
+ }
443
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
444
+ wrapper: TestWrapper,
445
+ });
446
+ await (0, react_1.act)(async () => {
447
+ await result.current.mutateAsync({
448
+ message: {
449
+ role: "user",
450
+ content: [{ type: "text", text: "Calculate" }],
451
+ },
452
+ });
453
+ });
454
+ expect(toolExecuted).toHaveBeenCalledWith({ a: 10, b: 20 });
455
+ });
456
+ it("handles missing TOOL_CALL_ARGS gracefully", async () => {
457
+ // Test that tools can be executed even when no args events are received
458
+ // (the hook keeps input as empty object)
459
+ const toolExecuted = jest.fn().mockResolvedValue("result");
460
+ const testTool = {
461
+ name: "test_tool",
462
+ description: "Test tool",
463
+ tool: toolExecuted,
464
+ inputSchema: zod_1.z.object({}),
465
+ outputSchema: zod_1.z.string(),
466
+ };
467
+ const mockRegistry = {
468
+ componentList: new Map(),
469
+ toolRegistry: new Map([["test_tool", testTool]]),
470
+ };
471
+ const initialStream = createAsyncIterator([
472
+ {
473
+ type: core_1.EventType.RUN_STARTED,
474
+ runId: "run_1",
475
+ threadId: "thread_123",
476
+ },
477
+ {
478
+ type: core_1.EventType.TEXT_MESSAGE_START,
479
+ messageId: "msg_1",
480
+ role: "assistant",
481
+ },
482
+ {
483
+ type: core_1.EventType.TOOL_CALL_START,
484
+ toolCallId: "call_1",
485
+ toolCallName: "test_tool",
486
+ parentMessageId: "msg_1",
487
+ },
488
+ // No TOOL_CALL_ARGS events - args will be empty
489
+ {
490
+ type: core_1.EventType.TOOL_CALL_END,
491
+ toolCallId: "call_1",
492
+ },
493
+ {
494
+ type: core_1.EventType.CUSTOM,
495
+ name: "tambo.run.awaiting_input",
496
+ value: { pendingToolCallIds: ["call_1"] },
497
+ },
498
+ ]);
499
+ const continueStream = createAsyncIterator([
500
+ {
501
+ type: core_1.EventType.RUN_STARTED,
502
+ runId: "run_2",
503
+ threadId: "thread_123",
504
+ },
505
+ { type: core_1.EventType.RUN_FINISHED },
506
+ ]);
507
+ mockThreadsRunsApi.run
508
+ .mockResolvedValueOnce(initialStream)
509
+ .mockResolvedValueOnce(continueStream);
510
+ function TestWrapper({ children }) {
511
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
512
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
513
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
514
+ }
515
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
516
+ wrapper: TestWrapper,
517
+ });
518
+ await (0, react_1.act)(async () => {
519
+ await result.current.mutateAsync({
520
+ message: {
521
+ role: "user",
522
+ content: [{ type: "text", text: "Test" }],
523
+ },
524
+ });
525
+ });
526
+ // Tool should be called with empty input due to no args events
527
+ expect(toolExecuted).toHaveBeenCalledWith({});
528
+ });
529
+ it("handles unknown tool in awaiting_input by returning error result", async () => {
530
+ const mockRegistry = {
531
+ componentList: new Map(),
532
+ toolRegistry: new Map(), // Empty registry - tool not found
533
+ };
534
+ const initialStream = createAsyncIterator([
535
+ {
536
+ type: core_1.EventType.RUN_STARTED,
537
+ runId: "run_1",
538
+ threadId: "thread_123",
539
+ },
540
+ {
541
+ type: core_1.EventType.TEXT_MESSAGE_START,
542
+ messageId: "msg_1",
543
+ role: "assistant",
544
+ },
545
+ {
546
+ type: core_1.EventType.TOOL_CALL_START,
547
+ toolCallId: "call_1",
548
+ toolCallName: "unknown_tool",
549
+ parentMessageId: "msg_1",
550
+ },
551
+ {
552
+ type: core_1.EventType.TOOL_CALL_ARGS,
553
+ toolCallId: "call_1",
554
+ delta: "{}",
555
+ },
556
+ {
557
+ type: core_1.EventType.TOOL_CALL_END,
558
+ toolCallId: "call_1",
559
+ },
560
+ {
561
+ type: core_1.EventType.CUSTOM,
562
+ name: "tambo.run.awaiting_input",
563
+ value: { pendingToolCallIds: ["call_1"] },
564
+ },
565
+ ]);
566
+ const continueStream = createAsyncIterator([
567
+ {
568
+ type: core_1.EventType.RUN_STARTED,
569
+ runId: "run_2",
570
+ threadId: "thread_123",
571
+ },
572
+ { type: core_1.EventType.RUN_FINISHED },
573
+ ]);
574
+ mockThreadsRunsApi.run
575
+ .mockResolvedValueOnce(initialStream)
576
+ .mockResolvedValueOnce(continueStream);
577
+ function TestWrapper({ children }) {
578
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
579
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
580
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
581
+ }
582
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
583
+ wrapper: TestWrapper,
584
+ });
585
+ await (0, react_1.act)(async () => {
586
+ await result.current.mutateAsync({
587
+ message: {
588
+ role: "user",
589
+ content: [{ type: "text", text: "Test" }],
590
+ },
591
+ });
592
+ });
593
+ // Verify continuation was called (second call)
594
+ expect(mockThreadsRunsApi.run).toHaveBeenCalledTimes(2);
595
+ // Continuation should include error message for unknown tool
596
+ const continueCall = mockThreadsRunsApi.run.mock.calls[1];
597
+ expect(continueCall[1].message.content[0]).toEqual({
598
+ type: "tool_result",
599
+ toolUseId: "call_1",
600
+ content: [
601
+ { type: "text", text: 'Tool "unknown_tool" not found in registry' },
602
+ ],
603
+ });
604
+ });
605
+ it("works with default registry context when no provider is present", () => {
606
+ // TamboRegistryContext has a default value, so the hook should work
607
+ // (though with an empty registry)
608
+ function TestWrapperWithoutRegistry({ children, }) {
609
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
610
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children)));
611
+ }
612
+ // Should not throw - default context is used
613
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
614
+ wrapper: TestWrapperWithoutRegistry,
615
+ });
616
+ expect(result.current.mutate).toBeDefined();
617
+ });
618
+ it("invalidates queries on successful mutation", async () => {
619
+ const mockStream = createAsyncIterator([
620
+ {
621
+ type: core_1.EventType.RUN_STARTED,
622
+ runId: "run_1",
623
+ threadId: "thread_123",
624
+ },
625
+ { type: core_1.EventType.RUN_FINISHED },
626
+ ]);
627
+ mockThreadsRunsApi.run.mockResolvedValue(mockStream);
628
+ const mockRegistry = {
629
+ componentList: new Map(),
630
+ toolRegistry: new Map(),
631
+ };
632
+ function TestWrapper({ children }) {
633
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
634
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
635
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
636
+ }
637
+ const invalidateQueriesSpy = jest.spyOn(queryClient, "invalidateQueries");
638
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
639
+ wrapper: TestWrapper,
640
+ });
641
+ await (0, react_1.act)(async () => {
642
+ await result.current.mutateAsync({
643
+ message: {
644
+ role: "user",
645
+ content: [{ type: "text", text: "Hello" }],
646
+ },
647
+ });
648
+ });
649
+ await (0, react_1.waitFor)(() => {
650
+ expect(invalidateQueriesSpy).toHaveBeenCalledWith({
651
+ queryKey: ["v1-threads", "thread_123"],
652
+ });
653
+ });
654
+ });
655
+ it("handles multi-round tool execution (tool→AI→tool→AI)", async () => {
656
+ const tool1Executed = jest.fn().mockResolvedValue("result from tool 1");
657
+ const tool2Executed = jest.fn().mockResolvedValue("result from tool 2");
658
+ const tool1 = {
659
+ name: "tool_1",
660
+ description: "First tool",
661
+ tool: tool1Executed,
662
+ inputSchema: zod_1.z.object({ input: zod_1.z.string() }),
663
+ outputSchema: zod_1.z.string(),
664
+ };
665
+ const tool2 = {
666
+ name: "tool_2",
667
+ description: "Second tool",
668
+ tool: tool2Executed,
669
+ inputSchema: zod_1.z.object({ input: zod_1.z.string() }),
670
+ outputSchema: zod_1.z.string(),
671
+ };
672
+ const mockRegistry = {
673
+ componentList: new Map(),
674
+ toolRegistry: new Map([
675
+ ["tool_1", tool1],
676
+ ["tool_2", tool2],
677
+ ]),
678
+ };
679
+ // Initial stream: AI calls tool_1
680
+ const initialStream = createAsyncIterator([
681
+ {
682
+ type: core_1.EventType.RUN_STARTED,
683
+ runId: "run_1",
684
+ threadId: "thread_123",
685
+ },
686
+ {
687
+ type: core_1.EventType.TEXT_MESSAGE_START,
688
+ messageId: "msg_1",
689
+ role: "assistant",
690
+ },
691
+ {
692
+ type: core_1.EventType.TOOL_CALL_START,
693
+ toolCallId: "call_1",
694
+ toolCallName: "tool_1",
695
+ parentMessageId: "msg_1",
696
+ },
697
+ {
698
+ type: core_1.EventType.TOOL_CALL_ARGS,
699
+ toolCallId: "call_1",
700
+ delta: '{"input":"first"}',
701
+ },
702
+ { type: core_1.EventType.TOOL_CALL_END, toolCallId: "call_1" },
703
+ {
704
+ type: core_1.EventType.CUSTOM,
705
+ name: "tambo.run.awaiting_input",
706
+ value: { pendingToolCallIds: ["call_1"] },
707
+ },
708
+ ]);
709
+ // Second stream: AI receives tool_1 result, then calls tool_2
710
+ const secondStream = createAsyncIterator([
711
+ {
712
+ type: core_1.EventType.RUN_STARTED,
713
+ runId: "run_2",
714
+ threadId: "thread_123",
715
+ },
716
+ {
717
+ type: core_1.EventType.TEXT_MESSAGE_START,
718
+ messageId: "msg_2",
719
+ role: "assistant",
720
+ },
721
+ {
722
+ type: core_1.EventType.TOOL_CALL_START,
723
+ toolCallId: "call_2",
724
+ toolCallName: "tool_2",
725
+ parentMessageId: "msg_2",
726
+ },
727
+ {
728
+ type: core_1.EventType.TOOL_CALL_ARGS,
729
+ toolCallId: "call_2",
730
+ delta: '{"input":"second"}',
731
+ },
732
+ { type: core_1.EventType.TOOL_CALL_END, toolCallId: "call_2" },
733
+ {
734
+ type: core_1.EventType.CUSTOM,
735
+ name: "tambo.run.awaiting_input",
736
+ value: { pendingToolCallIds: ["call_2"] },
737
+ },
738
+ ]);
739
+ // Third stream: AI receives tool_2 result, finishes
740
+ const thirdStream = createAsyncIterator([
741
+ {
742
+ type: core_1.EventType.RUN_STARTED,
743
+ runId: "run_3",
744
+ threadId: "thread_123",
745
+ },
746
+ { type: core_1.EventType.RUN_FINISHED },
747
+ ]);
748
+ mockThreadsRunsApi.run
749
+ .mockResolvedValueOnce(initialStream)
750
+ .mockResolvedValueOnce(secondStream)
751
+ .mockResolvedValueOnce(thirdStream);
752
+ function TestWrapper({ children }) {
753
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
754
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
755
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
756
+ }
757
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
758
+ wrapper: TestWrapper,
759
+ });
760
+ await (0, react_1.act)(async () => {
761
+ await result.current.mutateAsync({
762
+ message: {
763
+ role: "user",
764
+ content: [{ type: "text", text: "Hello" }],
765
+ },
766
+ });
767
+ });
768
+ // Both tools should have been executed
769
+ expect(tool1Executed).toHaveBeenCalledWith({ input: "first" });
770
+ expect(tool2Executed).toHaveBeenCalledWith({ input: "second" });
771
+ // Should have made 3 API calls (initial + 2 continuations)
772
+ expect(mockThreadsRunsApi.run).toHaveBeenCalledTimes(3);
773
+ // First continuation should have tool_1 result with previousRunId: run_1
774
+ const firstContinue = mockThreadsRunsApi.run.mock.calls[1];
775
+ expect(firstContinue[1].previousRunId).toBe("run_1");
776
+ expect(firstContinue[1].message.content[0]).toEqual({
777
+ type: "tool_result",
778
+ toolUseId: "call_1",
779
+ content: [{ type: "text", text: "result from tool 1" }],
780
+ });
781
+ // Second continuation should have tool_2 result with previousRunId: run_2
782
+ const secondContinue = mockThreadsRunsApi.run.mock.calls[2];
783
+ expect(secondContinue[1].previousRunId).toBe("run_2");
784
+ expect(secondContinue[1].message.content[0]).toEqual({
785
+ type: "tool_result",
786
+ toolUseId: "call_2",
787
+ content: [{ type: "text", text: "result from tool 2" }],
788
+ });
789
+ });
790
+ it("logs error on mutation failure", async () => {
791
+ const consoleSpy = jest
792
+ .spyOn(console, "error")
793
+ .mockImplementation(() => { });
794
+ const testError = new Error("API Error");
795
+ mockThreadsRunsApi.run.mockRejectedValue(testError);
796
+ const mockRegistry = {
797
+ componentList: new Map(),
798
+ toolRegistry: new Map(),
799
+ };
800
+ function TestWrapper({ children }) {
801
+ return (react_2.default.createElement(react_query_1.QueryClientProvider, { client: queryClient },
802
+ react_2.default.createElement(tambo_registry_provider_1.TamboRegistryContext.Provider, { value: mockRegistry },
803
+ react_2.default.createElement(tambo_v1_stream_context_1.TamboV1StreamProvider, { threadId: "thread_123" }, children))));
804
+ }
805
+ const { result } = (0, react_1.renderHook)(() => (0, use_tambo_v1_send_message_1.useTamboV1SendMessage)("thread_123"), {
806
+ wrapper: TestWrapper,
807
+ });
808
+ try {
809
+ await (0, react_1.act)(async () => {
810
+ await result.current.mutateAsync({
811
+ message: {
812
+ role: "user",
813
+ content: [{ type: "text", text: "Hello" }],
814
+ },
815
+ });
816
+ });
817
+ }
818
+ catch {
819
+ // Expected to throw
820
+ }
821
+ await (0, react_1.waitFor)(() => {
822
+ expect(consoleSpy).toHaveBeenCalledWith("[useTamboV1SendMessage] Mutation failed:", testError);
823
+ });
824
+ consoleSpy.mockRestore();
825
+ });
826
+ });
827
+ //# sourceMappingURL=use-tambo-v1-send-message.test.js.map