@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,715 @@
1
+ "use strict";
2
+ /**
3
+ * Event Accumulation Logic for v1 Streaming API
4
+ *
5
+ * Implements a reducer that transforms AG-UI event streams into React state.
6
+ * Used with useReducer to accumulate events into thread state.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.UnreachableCaseError = void 0;
10
+ exports.createInitialThreadState = createInitialThreadState;
11
+ exports.createInitialState = createInitialState;
12
+ exports.streamReducer = streamReducer;
13
+ const core_1 = require("@ag-ui/core");
14
+ const event_1 = require("../types/event");
15
+ const json_patch_1 = require("./json-patch");
16
+ /**
17
+ * Error thrown when an unreachable case is reached in a switch statement.
18
+ * This indicates a programming error where not all cases were handled.
19
+ */
20
+ class UnreachableCaseError extends Error {
21
+ constructor(value) {
22
+ super(`Unreachable case: ${JSON.stringify(value)}`);
23
+ this.name = "UnreachableCaseError";
24
+ }
25
+ }
26
+ exports.UnreachableCaseError = UnreachableCaseError;
27
+ /**
28
+ * Initial streaming state.
29
+ */
30
+ const initialStreamingState = {
31
+ status: "idle",
32
+ };
33
+ /**
34
+ * Create initial thread state for a new thread.
35
+ * @param threadId - Unique thread identifier
36
+ * @returns Initial thread state
37
+ */
38
+ function createInitialThreadState(threadId) {
39
+ const now = new Date().toISOString();
40
+ return {
41
+ thread: {
42
+ id: threadId,
43
+ messages: [],
44
+ status: "idle",
45
+ createdAt: now,
46
+ updatedAt: now,
47
+ },
48
+ streaming: initialStreamingState,
49
+ accumulatingToolArgs: new Map(),
50
+ };
51
+ }
52
+ /**
53
+ * Create initial stream state with empty threadMap.
54
+ * @returns Initial stream state
55
+ */
56
+ function createInitialState() {
57
+ return {
58
+ threadMap: {},
59
+ currentThreadId: null,
60
+ };
61
+ }
62
+ /**
63
+ * Replace a message at a specific index immutably.
64
+ * @param messages - Current messages array
65
+ * @param index - Index of message to replace
66
+ * @param updatedMessage - New message to insert
67
+ * @returns New messages array with the message replaced
68
+ */
69
+ function updateMessageAtIndex(messages, index, updatedMessage) {
70
+ return [
71
+ ...messages.slice(0, index),
72
+ updatedMessage,
73
+ ...messages.slice(index + 1),
74
+ ];
75
+ }
76
+ /**
77
+ * Replace a content block at a specific index within a message's content immutably.
78
+ * @param content - Current content array
79
+ * @param index - Index of content to replace
80
+ * @param updatedContent - New content to insert
81
+ * @returns New content array with the content replaced
82
+ */
83
+ function updateContentAtIndex(content, index, updatedContent) {
84
+ return [
85
+ ...content.slice(0, index),
86
+ updatedContent,
87
+ ...content.slice(index + 1),
88
+ ];
89
+ }
90
+ /**
91
+ * Find a content block by ID across all messages, searching from most recent.
92
+ *
93
+ * TODO: This is O(n*m) where n = messages and m = content blocks per message.
94
+ * For high-frequency streaming with many messages, consider maintaining an
95
+ * index map of contentId -> {messageIndex, contentIndex} that gets updated
96
+ * when content blocks are created.
97
+ * @param messages - Messages to search
98
+ * @param contentType - Type of content to find ("component" or "tool_use")
99
+ * @param contentId - ID of the content block
100
+ * @param eventName - Name of the event (for error messages)
101
+ * @returns Location of the content block
102
+ * @throws {Error} If content not found
103
+ */
104
+ function findContentById(messages, contentType, contentId, eventName) {
105
+ for (let i = messages.length - 1; i >= 0; i--) {
106
+ const idx = messages[i].content.findIndex((c) => c.type === contentType && c.id === contentId);
107
+ if (idx !== -1) {
108
+ return { messageIndex: i, contentIndex: idx };
109
+ }
110
+ }
111
+ throw new Error(`${contentType} ${contentId} not found for ${eventName}`);
112
+ }
113
+ /**
114
+ * Create updated thread state with new messages.
115
+ * @param threadState - Current thread state
116
+ * @param messages - New messages array
117
+ * @returns Updated thread state
118
+ */
119
+ function updateThreadMessages(threadState, messages) {
120
+ return {
121
+ ...threadState,
122
+ thread: {
123
+ ...threadState.thread,
124
+ messages,
125
+ updatedAt: new Date().toISOString(),
126
+ },
127
+ };
128
+ }
129
+ /**
130
+ * Stream reducer that accumulates events into thread state.
131
+ *
132
+ * This reducer handles all AG-UI events and Tambo custom events,
133
+ * transforming them into immutable state updates per thread.
134
+ * @param state - Current stream state
135
+ * @param action - Action to process
136
+ * @returns Updated stream state
137
+ */
138
+ function streamReducer(state, action) {
139
+ // Handle non-event actions first
140
+ switch (action.type) {
141
+ case "INIT_THREAD": {
142
+ const { threadId, initialThread } = action;
143
+ // Don't overwrite existing thread
144
+ if (state.threadMap[threadId]) {
145
+ return state;
146
+ }
147
+ const baseState = createInitialThreadState(threadId);
148
+ const threadState = initialThread
149
+ ? {
150
+ ...baseState,
151
+ thread: {
152
+ ...baseState.thread,
153
+ ...initialThread,
154
+ id: threadId,
155
+ },
156
+ }
157
+ : baseState;
158
+ return {
159
+ ...state,
160
+ threadMap: {
161
+ ...state.threadMap,
162
+ [threadId]: threadState,
163
+ },
164
+ };
165
+ }
166
+ case "SET_CURRENT_THREAD": {
167
+ return {
168
+ ...state,
169
+ currentThreadId: action.threadId,
170
+ };
171
+ }
172
+ case "START_NEW_THREAD": {
173
+ // Atomic action: initialize thread AND set as current in one reducer pass
174
+ // This prevents race conditions when multiple startNewThread() calls happen
175
+ const { threadId, initialThread } = action;
176
+ // Don't overwrite existing thread
177
+ if (state.threadMap[threadId]) {
178
+ return {
179
+ ...state,
180
+ currentThreadId: threadId,
181
+ };
182
+ }
183
+ const baseState = createInitialThreadState(threadId);
184
+ const threadState = initialThread
185
+ ? {
186
+ ...baseState,
187
+ thread: {
188
+ ...baseState.thread,
189
+ ...initialThread,
190
+ id: threadId,
191
+ },
192
+ }
193
+ : baseState;
194
+ return {
195
+ ...state,
196
+ threadMap: {
197
+ ...state.threadMap,
198
+ [threadId]: threadState,
199
+ },
200
+ currentThreadId: threadId,
201
+ };
202
+ }
203
+ case "EVENT":
204
+ // Fall through to event handling below
205
+ break;
206
+ }
207
+ // Handle EVENT action
208
+ const { event, threadId } = action;
209
+ // Get the current thread state, auto-initializing if needed
210
+ // Auto-initialization handles the case where events arrive before explicit thread init
211
+ // (e.g., when creating a new thread and RUN_STARTED is the first event)
212
+ let threadState = state.threadMap[threadId];
213
+ let updatedState = state;
214
+ if (!threadState) {
215
+ // Auto-initialize the thread to avoid dropping events
216
+ threadState = createInitialThreadState(threadId);
217
+ updatedState = {
218
+ ...state,
219
+ threadMap: {
220
+ ...state.threadMap,
221
+ [threadId]: threadState,
222
+ },
223
+ };
224
+ }
225
+ // Process the event for this specific thread
226
+ let updatedThreadState;
227
+ // Switch on event.type - AGUIEvent is a discriminated union so TypeScript
228
+ // automatically narrows the type in each case branch
229
+ switch (event.type) {
230
+ case core_1.EventType.RUN_STARTED:
231
+ updatedThreadState = handleRunStarted(threadState, event);
232
+ break;
233
+ case core_1.EventType.RUN_FINISHED:
234
+ updatedThreadState = handleRunFinished(threadState, event);
235
+ break;
236
+ case core_1.EventType.RUN_ERROR:
237
+ updatedThreadState = handleRunError(threadState, event);
238
+ break;
239
+ case core_1.EventType.TEXT_MESSAGE_START:
240
+ updatedThreadState = handleTextMessageStart(threadState, event);
241
+ break;
242
+ case core_1.EventType.TEXT_MESSAGE_CONTENT:
243
+ updatedThreadState = handleTextMessageContent(threadState, event);
244
+ break;
245
+ case core_1.EventType.TEXT_MESSAGE_END:
246
+ updatedThreadState = handleTextMessageEnd(threadState, event);
247
+ break;
248
+ case core_1.EventType.TOOL_CALL_START:
249
+ updatedThreadState = handleToolCallStart(threadState, event);
250
+ break;
251
+ case core_1.EventType.TOOL_CALL_ARGS:
252
+ updatedThreadState = handleToolCallArgs(threadState, event);
253
+ break;
254
+ case core_1.EventType.TOOL_CALL_END:
255
+ updatedThreadState = handleToolCallEnd(threadState, event);
256
+ break;
257
+ case core_1.EventType.TOOL_CALL_RESULT:
258
+ updatedThreadState = handleToolCallResult(threadState, event);
259
+ break;
260
+ case core_1.EventType.CUSTOM:
261
+ updatedThreadState = handleCustomEvent(threadState, event);
262
+ break;
263
+ // Unsupported AG-UI event types - may be added in future phases
264
+ case core_1.EventType.TEXT_MESSAGE_CHUNK:
265
+ case core_1.EventType.THINKING_TEXT_MESSAGE_START:
266
+ case core_1.EventType.THINKING_TEXT_MESSAGE_CONTENT:
267
+ case core_1.EventType.THINKING_TEXT_MESSAGE_END:
268
+ case core_1.EventType.TOOL_CALL_CHUNK:
269
+ case core_1.EventType.THINKING_START:
270
+ case core_1.EventType.THINKING_END:
271
+ case core_1.EventType.STATE_SNAPSHOT:
272
+ case core_1.EventType.STATE_DELTA:
273
+ case core_1.EventType.MESSAGES_SNAPSHOT:
274
+ case core_1.EventType.ACTIVITY_SNAPSHOT:
275
+ case core_1.EventType.ACTIVITY_DELTA:
276
+ case core_1.EventType.RAW:
277
+ case core_1.EventType.STEP_STARTED:
278
+ case core_1.EventType.STEP_FINISHED:
279
+ // Log warning - these events are being ignored
280
+ console.warn(`[StreamReducer] Received unsupported event type: ${event.type}. ` +
281
+ `This event will be ignored.`);
282
+ return updatedState;
283
+ default: {
284
+ // Exhaustiveness check: if a new event type is added to AGUIEvent
285
+ // and not handled above, TypeScript will error here
286
+ const _exhaustiveCheck = event;
287
+ throw new UnreachableCaseError(_exhaustiveCheck);
288
+ }
289
+ }
290
+ // Return updated state with modified thread
291
+ return {
292
+ ...updatedState,
293
+ threadMap: {
294
+ ...updatedState.threadMap,
295
+ [threadId]: updatedThreadState,
296
+ },
297
+ };
298
+ }
299
+ /**
300
+ * Handle RUN_STARTED event.
301
+ * @param threadState - Current thread state
302
+ * @param event - Run started event
303
+ * @returns Updated thread state
304
+ */
305
+ function handleRunStarted(threadState, event) {
306
+ return {
307
+ ...threadState,
308
+ thread: {
309
+ ...threadState.thread,
310
+ status: "streaming",
311
+ updatedAt: new Date().toISOString(),
312
+ },
313
+ streaming: {
314
+ status: "streaming",
315
+ runId: event.runId,
316
+ startTime: event.timestamp ?? Date.now(),
317
+ },
318
+ };
319
+ }
320
+ /**
321
+ * Handle RUN_FINISHED event.
322
+ * @param threadState - Current thread state
323
+ * @param _event - Run finished event (unused)
324
+ * @returns Updated thread state
325
+ */
326
+ function handleRunFinished(threadState, _event) {
327
+ return {
328
+ ...threadState,
329
+ thread: {
330
+ ...threadState.thread,
331
+ status: "complete",
332
+ updatedAt: new Date().toISOString(),
333
+ },
334
+ streaming: {
335
+ ...threadState.streaming,
336
+ status: "complete",
337
+ },
338
+ };
339
+ }
340
+ /**
341
+ * Handle RUN_ERROR event.
342
+ * @param threadState - Current thread state
343
+ * @param event - Run error event
344
+ * @returns Updated thread state
345
+ */
346
+ function handleRunError(threadState, event) {
347
+ return {
348
+ ...threadState,
349
+ thread: {
350
+ ...threadState.thread,
351
+ status: "error",
352
+ updatedAt: new Date().toISOString(),
353
+ },
354
+ streaming: {
355
+ ...threadState.streaming,
356
+ status: "error",
357
+ error: {
358
+ message: event.message,
359
+ code: event.code,
360
+ },
361
+ },
362
+ };
363
+ }
364
+ /**
365
+ * Handle TEXT_MESSAGE_START event.
366
+ * Creates a new message in the thread.
367
+ * @param threadState - Current thread state
368
+ * @param event - Text message start event
369
+ * @returns Updated thread state
370
+ */
371
+ function handleTextMessageStart(threadState, event) {
372
+ const newMessage = {
373
+ id: event.messageId,
374
+ role: event.role === "user" ? "user" : "assistant",
375
+ content: [],
376
+ createdAt: new Date().toISOString(),
377
+ };
378
+ return {
379
+ ...threadState,
380
+ thread: {
381
+ ...threadState.thread,
382
+ messages: [...threadState.thread.messages, newMessage],
383
+ updatedAt: new Date().toISOString(),
384
+ },
385
+ streaming: {
386
+ ...threadState.streaming,
387
+ messageId: event.messageId,
388
+ },
389
+ };
390
+ }
391
+ /**
392
+ * Handle TEXT_MESSAGE_CONTENT event.
393
+ * Appends text content to the current message.
394
+ * @param threadState - Current thread state
395
+ * @param event - Text message content event
396
+ * @returns Updated thread state
397
+ */
398
+ function handleTextMessageContent(threadState, event) {
399
+ const messageId = event.messageId;
400
+ const messages = threadState.thread.messages;
401
+ // Find the message to update
402
+ const messageIndex = messages.findIndex((m) => m.id === messageId);
403
+ if (messageIndex === -1) {
404
+ throw new Error(`Message ${messageId} not found for TEXT_MESSAGE_CONTENT event`);
405
+ }
406
+ const message = messages[messageIndex];
407
+ const content = message.content;
408
+ // Find or create text content block
409
+ const lastContent = content[content.length - 1];
410
+ const isTextBlock = lastContent?.type === "text";
411
+ const updatedContent = isTextBlock
412
+ ? [
413
+ ...content.slice(0, -1),
414
+ {
415
+ ...lastContent,
416
+ text: lastContent.text + event.delta,
417
+ },
418
+ ]
419
+ : [
420
+ ...content,
421
+ {
422
+ type: "text",
423
+ text: event.delta,
424
+ },
425
+ ];
426
+ const updatedMessage = {
427
+ ...message,
428
+ content: updatedContent,
429
+ };
430
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
431
+ }
432
+ /**
433
+ * Handle TEXT_MESSAGE_END event.
434
+ * Marks the message as complete.
435
+ * @param threadState - Current thread state
436
+ * @param event - Text message end event
437
+ * @returns Updated thread state
438
+ */
439
+ function handleTextMessageEnd(threadState, event) {
440
+ const activeMessageId = threadState.streaming.messageId;
441
+ if (activeMessageId && event.messageId !== activeMessageId) {
442
+ throw new Error(`TEXT_MESSAGE_END messageId mismatch (thread ${threadState.thread.id}): expected ${activeMessageId}, got ${event.messageId}`);
443
+ }
444
+ return {
445
+ ...threadState,
446
+ streaming: {
447
+ ...threadState.streaming,
448
+ messageId: undefined,
449
+ },
450
+ };
451
+ }
452
+ /**
453
+ * Handle TOOL_CALL_START event.
454
+ * Adds a tool use content block to the current message.
455
+ * @param threadState - Current thread state
456
+ * @param event - Tool call start event
457
+ * @returns Updated thread state
458
+ */
459
+ function handleToolCallStart(threadState, event) {
460
+ const messageId = event.parentMessageId;
461
+ const messages = threadState.thread.messages;
462
+ // If no parent message ID, use the last message
463
+ const messageIndex = messageId
464
+ ? messages.findIndex((m) => m.id === messageId)
465
+ : messages.length - 1;
466
+ if (messageIndex === -1) {
467
+ throw new Error(messageId
468
+ ? `Message ${messageId} not found for TOOL_CALL_START event`
469
+ : `No messages exist for TOOL_CALL_START event`);
470
+ }
471
+ const message = messages[messageIndex];
472
+ const newContent = {
473
+ type: "tool_use",
474
+ id: event.toolCallId,
475
+ name: event.toolCallName,
476
+ input: {},
477
+ };
478
+ const updatedMessage = {
479
+ ...message,
480
+ content: [...message.content, newContent],
481
+ };
482
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
483
+ }
484
+ /**
485
+ * Handle TOOL_CALL_ARGS event.
486
+ * Accumulates JSON string deltas for tool call arguments.
487
+ * The accumulated string will be parsed at TOOL_CALL_END.
488
+ * @param threadState - Current thread state
489
+ * @param event - Tool call args event
490
+ * @returns Updated thread state
491
+ */
492
+ function handleToolCallArgs(threadState, event) {
493
+ const toolCallId = event.toolCallId;
494
+ // Accumulate the JSON string delta
495
+ const accumulatedArgs = threadState.accumulatingToolArgs;
496
+ const existingArgs = accumulatedArgs.get(toolCallId) ?? "";
497
+ const newAccumulatedArgs = new Map(accumulatedArgs);
498
+ newAccumulatedArgs.set(toolCallId, existingArgs + event.delta);
499
+ return {
500
+ ...threadState,
501
+ accumulatingToolArgs: newAccumulatedArgs,
502
+ };
503
+ }
504
+ /**
505
+ * Handle TOOL_CALL_END event.
506
+ * Parses the accumulated JSON arguments and updates the tool_use content block.
507
+ * @param threadState - Current thread state
508
+ * @param event - Tool call end event
509
+ * @returns Updated thread state
510
+ */
511
+ function handleToolCallEnd(threadState, event) {
512
+ const toolCallId = event.toolCallId;
513
+ const messages = threadState.thread.messages;
514
+ // Get accumulated JSON args string
515
+ const accumulatedJson = threadState.accumulatingToolArgs.get(toolCallId);
516
+ if (!accumulatedJson) {
517
+ // No args accumulated - tool call has empty input
518
+ return threadState;
519
+ }
520
+ // Parse the accumulated JSON
521
+ let parsedInput;
522
+ try {
523
+ parsedInput = JSON.parse(accumulatedJson);
524
+ }
525
+ catch (error) {
526
+ throw new Error(`Failed to parse tool call arguments for ${toolCallId}: ${error instanceof Error ? error.message : String(error)}. JSON: ${accumulatedJson}`);
527
+ }
528
+ // Find the tool_use content block
529
+ const { messageIndex, contentIndex } = findContentById(messages, "tool_use", toolCallId, "TOOL_CALL_END event");
530
+ const message = messages[messageIndex];
531
+ const toolUseContent = message.content[contentIndex];
532
+ if (toolUseContent.type !== "tool_use") {
533
+ throw new Error(`Content at index ${contentIndex} is not a tool_use block for TOOL_CALL_END event`);
534
+ }
535
+ // Update the tool_use content with parsed input
536
+ const updatedContent = {
537
+ ...toolUseContent,
538
+ input: parsedInput,
539
+ };
540
+ const updatedMessage = {
541
+ ...message,
542
+ content: updateContentAtIndex(message.content, contentIndex, updatedContent),
543
+ };
544
+ // Clear accumulated args for this tool call
545
+ const newAccumulatingToolArgs = new Map(threadState.accumulatingToolArgs);
546
+ newAccumulatingToolArgs.delete(toolCallId);
547
+ return {
548
+ ...updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage)),
549
+ accumulatingToolArgs: newAccumulatingToolArgs,
550
+ };
551
+ }
552
+ /**
553
+ * Handle TOOL_CALL_RESULT event.
554
+ * Adds tool result to the message.
555
+ * @param threadState - Current thread state
556
+ * @param event - Tool call result event
557
+ * @returns Updated thread state
558
+ */
559
+ function handleToolCallResult(threadState, event) {
560
+ const messageId = event.messageId;
561
+ const messages = threadState.thread.messages;
562
+ // Find the message
563
+ const messageIndex = messages.findIndex((m) => m.id === messageId);
564
+ if (messageIndex === -1) {
565
+ throw new Error(`Message ${messageId} not found for TOOL_CALL_RESULT event`);
566
+ }
567
+ const message = messages[messageIndex];
568
+ // Add tool result content
569
+ const newContent = {
570
+ type: "tool_result",
571
+ toolUseId: event.toolCallId,
572
+ content: [
573
+ {
574
+ type: "text",
575
+ text: event.content,
576
+ },
577
+ ],
578
+ };
579
+ const updatedMessage = {
580
+ ...message,
581
+ content: [...message.content, newContent],
582
+ };
583
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
584
+ }
585
+ /**
586
+ * Handle custom events (Tambo-specific).
587
+ * @param threadState - Current thread state
588
+ * @param event - Custom event (already narrowed from AGUIEvent)
589
+ * @returns Updated thread state
590
+ */
591
+ function handleCustomEvent(threadState, event) {
592
+ // Use centralized casting function to get properly typed Tambo event
593
+ const customEvent = (0, event_1.asTamboCustomEvent)(event);
594
+ if (!customEvent) {
595
+ // Unknown custom event - log and return unchanged
596
+ console.warn(`[StreamReducer] Unknown custom event name: ${event.name}`);
597
+ return threadState;
598
+ }
599
+ switch (customEvent.name) {
600
+ case "tambo.component.start":
601
+ return handleComponentStart(threadState, customEvent);
602
+ case "tambo.component.props_delta":
603
+ return handleComponentDelta(threadState, customEvent, "props");
604
+ case "tambo.component.state_delta":
605
+ return handleComponentDelta(threadState, customEvent, "state");
606
+ case "tambo.component.end":
607
+ return handleComponentEnd(threadState, customEvent);
608
+ case "tambo.run.awaiting_input":
609
+ return handleRunAwaitingInput(threadState, customEvent);
610
+ default: {
611
+ // Exhaustiveness check: if a new event type is added to TamboCustomEvent
612
+ // and not handled here, TypeScript will error
613
+ const _exhaustiveCheck = customEvent;
614
+ throw new UnreachableCaseError(_exhaustiveCheck);
615
+ }
616
+ }
617
+ }
618
+ /**
619
+ * Handle tambo.component.start event.
620
+ * Adds a component content block to the message.
621
+ * @param threadState - Current thread state
622
+ * @param event - Component start event
623
+ * @returns Updated thread state
624
+ */
625
+ function handleComponentStart(threadState, event) {
626
+ const messageId = event.value.messageId;
627
+ const messages = threadState.thread.messages;
628
+ // Find the message
629
+ const messageIndex = messages.findIndex((m) => m.id === messageId);
630
+ if (messageIndex === -1) {
631
+ throw new Error(`Message ${messageId} not found for tambo.component.start event`);
632
+ }
633
+ const message = messages[messageIndex];
634
+ // Add component content block
635
+ const newContent = {
636
+ type: "component",
637
+ id: event.value.componentId,
638
+ name: event.value.componentName,
639
+ props: {},
640
+ };
641
+ const updatedMessage = {
642
+ ...message,
643
+ content: [...message.content, newContent],
644
+ };
645
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
646
+ }
647
+ /**
648
+ * Handle component delta events (both props_delta and state_delta).
649
+ * Applies JSON Patch to the specified field.
650
+ * @param threadState - Current thread state
651
+ * @param event - Component delta event (props or state)
652
+ * @param field - Which field to update ('props' or 'state')
653
+ * @returns Updated thread state
654
+ */
655
+ function handleComponentDelta(threadState, event, field) {
656
+ const componentId = event.value.componentId;
657
+ const operations = event.value.operations;
658
+ const messages = threadState.thread.messages;
659
+ const eventName = `tambo.component.${field}_delta`;
660
+ // Find the component content block
661
+ const { messageIndex, contentIndex } = findContentById(messages, "component", componentId, `${eventName} event`);
662
+ const message = messages[messageIndex];
663
+ const componentContent = message.content[contentIndex];
664
+ if (componentContent.type !== "component") {
665
+ throw new Error(`Content at index ${contentIndex} is not a component block for ${eventName} event`);
666
+ }
667
+ // Get current value (state defaults to {} if undefined)
668
+ const currentValue = field === "props"
669
+ ? componentContent.props
670
+ : (componentContent.state ?? {});
671
+ // Apply JSON Patch
672
+ const updatedValue = (0, json_patch_1.applyJsonPatch)(currentValue, operations);
673
+ const updatedContent = {
674
+ ...componentContent,
675
+ [field]: updatedValue,
676
+ };
677
+ const updatedMessage = {
678
+ ...message,
679
+ content: updateContentAtIndex(message.content, contentIndex, updatedContent),
680
+ };
681
+ return updateThreadMessages(threadState, updateMessageAtIndex(messages, messageIndex, updatedMessage));
682
+ }
683
+ /**
684
+ * Handle tambo.component.end event.
685
+ * Marks component as complete.
686
+ * @param threadState - Current thread state
687
+ * @param _event - Component end event (unused)
688
+ * @returns Updated thread state
689
+ */
690
+ function handleComponentEnd(threadState, _event) {
691
+ // For now, this doesn't change state
692
+ return threadState;
693
+ }
694
+ /**
695
+ * Handle tambo.run.awaiting_input event.
696
+ * Sets thread status to waiting for client-side tool execution.
697
+ * @param threadState - Current thread state
698
+ * @param _event - Run awaiting input event (unused)
699
+ * @returns Updated thread state
700
+ */
701
+ function handleRunAwaitingInput(threadState, _event) {
702
+ return {
703
+ ...threadState,
704
+ thread: {
705
+ ...threadState.thread,
706
+ status: "waiting",
707
+ updatedAt: new Date().toISOString(),
708
+ },
709
+ streaming: {
710
+ ...threadState.streaming,
711
+ status: "waiting",
712
+ },
713
+ };
714
+ }
715
+ //# sourceMappingURL=event-accumulator.js.map