@tambo-ai/react 0.49.0 → 0.53.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 (141) hide show
  1. package/dist/hooks/__tests__/use-component-state.test.js +4 -1
  2. package/dist/hooks/__tests__/use-component-state.test.js.map +1 -1
  3. package/dist/hooks/__tests__/use-message-images.test.d.ts +2 -0
  4. package/dist/hooks/__tests__/use-message-images.test.d.ts.map +1 -0
  5. package/dist/hooks/__tests__/use-message-images.test.js +66 -0
  6. package/dist/hooks/__tests__/use-message-images.test.js.map +1 -0
  7. package/dist/hooks/__tests__/use-tambo-threads.test.js +1 -1
  8. package/dist/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
  9. package/dist/hooks/use-component-state.js +3 -3
  10. package/dist/hooks/use-component-state.js.map +1 -1
  11. package/dist/hooks/use-message-images.d.ts +25 -0
  12. package/dist/hooks/use-message-images.d.ts.map +1 -0
  13. package/dist/hooks/use-message-images.js +66 -0
  14. package/dist/hooks/use-message-images.js.map +1 -0
  15. package/dist/hooks/use-suggestions.js +4 -2
  16. package/dist/hooks/use-suggestions.js.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/mcp/__tests__/mcp-client.test.d.ts +2 -0
  22. package/dist/mcp/__tests__/mcp-client.test.d.ts.map +1 -0
  23. package/dist/mcp/__tests__/mcp-client.test.js +502 -0
  24. package/dist/mcp/__tests__/mcp-client.test.js.map +1 -0
  25. package/dist/mcp/mcp-client.d.ts +77 -3
  26. package/dist/mcp/mcp-client.d.ts.map +1 -1
  27. package/dist/mcp/mcp-client.js +184 -19
  28. package/dist/mcp/mcp-client.js.map +1 -1
  29. package/dist/mcp/tambo-mcp-provider.d.ts +1 -0
  30. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  31. package/dist/mcp/tambo-mcp-provider.js +1 -0
  32. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  33. package/dist/model/tambo-interactable.d.ts +1 -1
  34. package/dist/model/tambo-interactable.d.ts.map +1 -1
  35. package/dist/model/tambo-interactable.js.map +1 -1
  36. package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts +2 -0
  37. package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts.map +1 -0
  38. package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.js +677 -0
  39. package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.js.map +1 -0
  40. package/dist/providers/__tests__/tambo-stubs.test.js +6 -2
  41. package/dist/providers/__tests__/tambo-stubs.test.js.map +1 -1
  42. package/dist/providers/__tests__/tambo-thread-provider.test.js +14 -14
  43. package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  44. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  45. package/dist/providers/tambo-interactable-provider.js +26 -24
  46. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  47. package/dist/providers/tambo-provider.d.ts +1 -0
  48. package/dist/providers/tambo-provider.d.ts.map +1 -1
  49. package/dist/providers/tambo-provider.js +1 -0
  50. package/dist/providers/tambo-provider.js.map +1 -1
  51. package/dist/providers/tambo-thread-input-provider.d.ts +11 -0
  52. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  53. package/dist/providers/tambo-thread-input-provider.js +63 -12
  54. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  55. package/dist/providers/tambo-thread-provider.d.ts +1 -0
  56. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  57. package/dist/providers/tambo-thread-provider.js +9 -5
  58. package/dist/providers/tambo-thread-provider.js.map +1 -1
  59. package/dist/setupTests.d.ts +0 -1
  60. package/dist/setupTests.d.ts.map +1 -1
  61. package/dist/setupTests.js +0 -1
  62. package/dist/setupTests.js.map +1 -1
  63. package/dist/util/__tests__/message-builder.test.d.ts +2 -0
  64. package/dist/util/__tests__/message-builder.test.d.ts.map +1 -0
  65. package/dist/util/__tests__/message-builder.test.js +191 -0
  66. package/dist/util/__tests__/message-builder.test.js.map +1 -0
  67. package/dist/util/message-builder.d.ts +10 -0
  68. package/dist/util/message-builder.d.ts.map +1 -0
  69. package/dist/util/message-builder.js +31 -0
  70. package/dist/util/message-builder.js.map +1 -0
  71. package/esm/hooks/__tests__/use-component-state.test.js +4 -1
  72. package/esm/hooks/__tests__/use-component-state.test.js.map +1 -1
  73. package/esm/hooks/__tests__/use-message-images.test.d.ts +2 -0
  74. package/esm/hooks/__tests__/use-message-images.test.d.ts.map +1 -0
  75. package/esm/hooks/__tests__/use-message-images.test.js +64 -0
  76. package/esm/hooks/__tests__/use-message-images.test.js.map +1 -0
  77. package/esm/hooks/__tests__/use-tambo-threads.test.js +1 -1
  78. package/esm/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
  79. package/esm/hooks/use-component-state.js +3 -3
  80. package/esm/hooks/use-component-state.js.map +1 -1
  81. package/esm/hooks/use-message-images.d.ts +25 -0
  82. package/esm/hooks/use-message-images.d.ts.map +1 -0
  83. package/esm/hooks/use-message-images.js +63 -0
  84. package/esm/hooks/use-message-images.js.map +1 -0
  85. package/esm/hooks/use-suggestions.js +4 -2
  86. package/esm/hooks/use-suggestions.js.map +1 -1
  87. package/esm/index.d.ts +1 -0
  88. package/esm/index.d.ts.map +1 -1
  89. package/esm/index.js +1 -0
  90. package/esm/index.js.map +1 -1
  91. package/esm/mcp/__tests__/mcp-client.test.d.ts +2 -0
  92. package/esm/mcp/__tests__/mcp-client.test.d.ts.map +1 -0
  93. package/esm/mcp/__tests__/mcp-client.test.js +500 -0
  94. package/esm/mcp/__tests__/mcp-client.test.js.map +1 -0
  95. package/esm/mcp/mcp-client.d.ts +77 -3
  96. package/esm/mcp/mcp-client.d.ts.map +1 -1
  97. package/esm/mcp/mcp-client.js +184 -19
  98. package/esm/mcp/mcp-client.js.map +1 -1
  99. package/esm/mcp/tambo-mcp-provider.d.ts +1 -0
  100. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  101. package/esm/mcp/tambo-mcp-provider.js +1 -0
  102. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  103. package/esm/model/tambo-interactable.d.ts +1 -1
  104. package/esm/model/tambo-interactable.d.ts.map +1 -1
  105. package/esm/model/tambo-interactable.js.map +1 -1
  106. package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts +2 -0
  107. package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts.map +1 -0
  108. package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.js +672 -0
  109. package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.js.map +1 -0
  110. package/esm/providers/__tests__/tambo-stubs.test.js +6 -2
  111. package/esm/providers/__tests__/tambo-stubs.test.js.map +1 -1
  112. package/esm/providers/__tests__/tambo-thread-provider.test.js +14 -14
  113. package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  114. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  115. package/esm/providers/tambo-interactable-provider.js +26 -24
  116. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  117. package/esm/providers/tambo-provider.d.ts +1 -0
  118. package/esm/providers/tambo-provider.d.ts.map +1 -1
  119. package/esm/providers/tambo-provider.js +1 -0
  120. package/esm/providers/tambo-provider.js.map +1 -1
  121. package/esm/providers/tambo-thread-input-provider.d.ts +11 -0
  122. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  123. package/esm/providers/tambo-thread-input-provider.js +63 -12
  124. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  125. package/esm/providers/tambo-thread-provider.d.ts +1 -0
  126. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  127. package/esm/providers/tambo-thread-provider.js +9 -5
  128. package/esm/providers/tambo-thread-provider.js.map +1 -1
  129. package/esm/setupTests.d.ts +0 -1
  130. package/esm/setupTests.d.ts.map +1 -1
  131. package/esm/setupTests.js +0 -1
  132. package/esm/setupTests.js.map +1 -1
  133. package/esm/util/__tests__/message-builder.test.d.ts +2 -0
  134. package/esm/util/__tests__/message-builder.test.d.ts.map +1 -0
  135. package/esm/util/__tests__/message-builder.test.js +189 -0
  136. package/esm/util/__tests__/message-builder.test.js.map +1 -0
  137. package/esm/util/message-builder.d.ts +10 -0
  138. package/esm/util/message-builder.d.ts.map +1 -0
  139. package/esm/util/message-builder.js +28 -0
  140. package/esm/util/message-builder.js.map +1 -0
  141. package/package.json +7 -7
@@ -0,0 +1,677 @@
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 react_1 = require("@testing-library/react");
7
+ const react_2 = __importDefault(require("react"));
8
+ const zod_1 = require("zod");
9
+ const tambo_interactable_provider_1 = require("../tambo-interactable-provider");
10
+ // Mock the context helpers
11
+ const mockAddContextHelper = jest.fn();
12
+ const mockRemoveContextHelper = jest.fn();
13
+ jest.mock("../tambo-context-helpers-provider", () => ({
14
+ TamboContextHelpersProvider: ({ children, }) => react_2.default.createElement(react_2.default.Fragment, null, children),
15
+ useTamboContextHelpers: () => ({
16
+ addContextHelper: mockAddContextHelper,
17
+ removeContextHelper: mockRemoveContextHelper,
18
+ }),
19
+ }));
20
+ // Mock the component provider
21
+ const mockRegisterTool = jest.fn();
22
+ jest.mock("../tambo-component-provider", () => ({
23
+ useTamboComponent: () => ({
24
+ registerTool: mockRegisterTool,
25
+ }),
26
+ }));
27
+ // Mock the context helper creation
28
+ jest.mock("../../context-helpers/current-interactables-context-helper", () => ({
29
+ createInteractablesContextHelper: () => jest.fn(() => ({
30
+ name: "interactables",
31
+ context: {
32
+ description: "Test interactables context",
33
+ components: [],
34
+ },
35
+ })),
36
+ }));
37
+ describe("updateInteractableComponentProps - Partial Updates", () => {
38
+ beforeEach(() => {
39
+ jest.clearAllMocks();
40
+ });
41
+ const wrapper = ({ children }) => (react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null, children));
42
+ describe("Partial Updates Functionality", () => {
43
+ it("should apply partial updates to existing props", () => {
44
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
45
+ const component = {
46
+ name: "TestComponent",
47
+ description: "A test component",
48
+ component: () => react_2.default.createElement("div", null, "Test"),
49
+ props: {
50
+ title: "Original Title",
51
+ count: 0,
52
+ active: true,
53
+ metadata: { type: "test", version: "1.0" },
54
+ },
55
+ propsSchema: zod_1.z.object({
56
+ title: zod_1.z.string(),
57
+ count: zod_1.z.number(),
58
+ active: zod_1.z.boolean(),
59
+ metadata: zod_1.z.object({
60
+ type: zod_1.z.string(),
61
+ version: zod_1.z.string(),
62
+ }),
63
+ }),
64
+ };
65
+ let componentId = "";
66
+ (0, react_1.act)(() => {
67
+ componentId = result.current.addInteractableComponent(component);
68
+ });
69
+ // Verify initial state
70
+ expect(result.current.interactableComponents[0].props).toEqual({
71
+ title: "Original Title",
72
+ count: 0,
73
+ active: true,
74
+ metadata: { type: "test", version: "1.0" },
75
+ });
76
+ // Apply partial update - only change count
77
+ let updateResult = "";
78
+ (0, react_1.act)(() => {
79
+ updateResult = result.current.updateInteractableComponentProps(componentId, {
80
+ count: 5,
81
+ });
82
+ });
83
+ expect(updateResult).toBe("Updated successfully");
84
+ expect(result.current.interactableComponents[0].props).toEqual({
85
+ title: "Original Title", // unchanged
86
+ count: 5, // updated
87
+ active: true, // unchanged
88
+ metadata: { type: "test", version: "1.0" }, // unchanged
89
+ });
90
+ });
91
+ it("should apply multiple partial updates in sequence", () => {
92
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
93
+ const component = {
94
+ name: "TestComponent",
95
+ description: "A test component",
96
+ component: () => react_2.default.createElement("div", null, "Test"),
97
+ props: {
98
+ title: "Original Title",
99
+ count: 0,
100
+ active: true,
101
+ description: "Original description",
102
+ },
103
+ propsSchema: zod_1.z.object({
104
+ title: zod_1.z.string(),
105
+ count: zod_1.z.number(),
106
+ active: zod_1.z.boolean(),
107
+ description: zod_1.z.string(),
108
+ }),
109
+ };
110
+ let componentId = "";
111
+ (0, react_1.act)(() => {
112
+ componentId = result.current.addInteractableComponent(component);
113
+ });
114
+ // First partial update - change title and count
115
+ (0, react_1.act)(() => {
116
+ result.current.updateInteractableComponentProps(componentId, {
117
+ title: "Updated Title",
118
+ count: 10,
119
+ });
120
+ });
121
+ expect(result.current.interactableComponents[0].props).toEqual({
122
+ title: "Updated Title",
123
+ count: 10,
124
+ active: true,
125
+ description: "Original description",
126
+ });
127
+ // Second partial update - change active and description
128
+ (0, react_1.act)(() => {
129
+ result.current.updateInteractableComponentProps(componentId, {
130
+ active: false,
131
+ description: "Updated description",
132
+ });
133
+ });
134
+ expect(result.current.interactableComponents[0].props).toEqual({
135
+ title: "Updated Title", // from previous update
136
+ count: 10, // from previous update
137
+ active: false, // new update
138
+ description: "Updated description", // new update
139
+ });
140
+ });
141
+ it("should handle nested object partial updates (shallow merge behavior)", () => {
142
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
143
+ const component = {
144
+ name: "TestComponent",
145
+ description: "A test component",
146
+ component: () => react_2.default.createElement("div", null, "Test"),
147
+ props: {
148
+ title: "Original Title",
149
+ config: {
150
+ theme: "light",
151
+ language: "en",
152
+ features: {
153
+ notifications: true,
154
+ analytics: false,
155
+ },
156
+ },
157
+ },
158
+ propsSchema: zod_1.z.object({
159
+ title: zod_1.z.string(),
160
+ config: zod_1.z.object({
161
+ theme: zod_1.z.string(),
162
+ language: zod_1.z.string(),
163
+ features: zod_1.z.object({
164
+ notifications: zod_1.z.boolean(),
165
+ analytics: zod_1.z.boolean(),
166
+ }),
167
+ }),
168
+ }),
169
+ };
170
+ let componentId = "";
171
+ (0, react_1.act)(() => {
172
+ componentId = result.current.addInteractableComponent(component);
173
+ });
174
+ // Partial update - replace entire config object (shallow merge behavior)
175
+ (0, react_1.act)(() => {
176
+ result.current.updateInteractableComponentProps(componentId, {
177
+ config: {
178
+ theme: "dark",
179
+ // Note: language and features are not provided, so they will be undefined
180
+ // This demonstrates the shallow merge behavior
181
+ },
182
+ });
183
+ });
184
+ expect(result.current.interactableComponents[0].props).toEqual({
185
+ title: "Original Title",
186
+ config: {
187
+ theme: "dark", // updated
188
+ // language and features are now undefined due to shallow merge
189
+ },
190
+ });
191
+ });
192
+ it("should handle array partial updates", () => {
193
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
194
+ const component = {
195
+ name: "TestComponent",
196
+ description: "A test component",
197
+ component: () => react_2.default.createElement("div", null, "Test"),
198
+ props: {
199
+ title: "Original Title",
200
+ items: ["item1", "item2", "item3"],
201
+ tags: ["tag1", "tag2"],
202
+ },
203
+ propsSchema: zod_1.z.object({
204
+ title: zod_1.z.string(),
205
+ items: zod_1.z.array(zod_1.z.string()),
206
+ tags: zod_1.z.array(zod_1.z.string()),
207
+ }),
208
+ };
209
+ let componentId = "";
210
+ (0, react_1.act)(() => {
211
+ componentId = result.current.addInteractableComponent(component);
212
+ });
213
+ // Partial update - only change items array
214
+ (0, react_1.act)(() => {
215
+ result.current.updateInteractableComponentProps(componentId, {
216
+ items: ["newItem1", "newItem2"],
217
+ });
218
+ });
219
+ expect(result.current.interactableComponents[0].props).toEqual({
220
+ title: "Original Title", // unchanged
221
+ items: ["newItem1", "newItem2"], // updated
222
+ tags: ["tag1", "tag2"], // unchanged
223
+ });
224
+ });
225
+ it("should handle null and undefined values in partial updates", () => {
226
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
227
+ const component = {
228
+ name: "TestComponent",
229
+ description: "A test component",
230
+ component: () => react_2.default.createElement("div", null, "Test"),
231
+ props: {
232
+ title: "Original Title",
233
+ count: 5,
234
+ description: "Original description",
235
+ },
236
+ propsSchema: zod_1.z.object({
237
+ title: zod_1.z.string(),
238
+ count: zod_1.z.number(),
239
+ description: zod_1.z.string(),
240
+ }),
241
+ };
242
+ let componentId = "";
243
+ (0, react_1.act)(() => {
244
+ componentId = result.current.addInteractableComponent(component);
245
+ });
246
+ // Partial update with null value
247
+ (0, react_1.act)(() => {
248
+ result.current.updateInteractableComponentProps(componentId, {
249
+ description: null,
250
+ });
251
+ });
252
+ expect(result.current.interactableComponents[0].props).toEqual({
253
+ title: "Original Title",
254
+ count: 5,
255
+ description: null,
256
+ });
257
+ // Partial update with undefined value
258
+ (0, react_1.act)(() => {
259
+ result.current.updateInteractableComponentProps(componentId, {
260
+ count: undefined,
261
+ });
262
+ });
263
+ expect(result.current.interactableComponents[0].props).toEqual({
264
+ title: "Original Title",
265
+ count: undefined,
266
+ description: null,
267
+ });
268
+ });
269
+ });
270
+ describe("Error Handling", () => {
271
+ it("should return error for non-existent component", () => {
272
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
273
+ let updateResult = "";
274
+ (0, react_1.act)(() => {
275
+ updateResult = result.current.updateInteractableComponentProps("non-existent", {
276
+ title: "New Title",
277
+ });
278
+ });
279
+ expect(updateResult).toBe("Updated successfully");
280
+ });
281
+ it("should return warning for empty props object", () => {
282
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
283
+ const component = {
284
+ name: "TestComponent",
285
+ description: "A test component",
286
+ component: () => react_2.default.createElement("div", null, "Test"),
287
+ props: { title: "Original Title" },
288
+ propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
289
+ };
290
+ let componentId = "";
291
+ (0, react_1.act)(() => {
292
+ componentId = result.current.addInteractableComponent(component);
293
+ });
294
+ let updateResult = "";
295
+ (0, react_1.act)(() => {
296
+ updateResult = result.current.updateInteractableComponentProps(componentId, {});
297
+ });
298
+ expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
299
+ });
300
+ it("should return warning for null props", () => {
301
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
302
+ const component = {
303
+ name: "TestComponent",
304
+ description: "A test component",
305
+ component: () => react_2.default.createElement("div", null, "Test"),
306
+ props: { title: "Original Title" },
307
+ propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
308
+ };
309
+ let componentId = "";
310
+ (0, react_1.act)(() => {
311
+ componentId = result.current.addInteractableComponent(component);
312
+ });
313
+ let updateResult = "";
314
+ (0, react_1.act)(() => {
315
+ updateResult = result.current.updateInteractableComponentProps(componentId, null);
316
+ });
317
+ expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
318
+ });
319
+ it("should return warning for undefined props", () => {
320
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
321
+ const component = {
322
+ name: "TestComponent",
323
+ description: "A test component",
324
+ component: () => react_2.default.createElement("div", null, "Test"),
325
+ props: { title: "Original Title" },
326
+ propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
327
+ };
328
+ let componentId = "";
329
+ (0, react_1.act)(() => {
330
+ componentId = result.current.addInteractableComponent(component);
331
+ });
332
+ let updateResult = "";
333
+ (0, react_1.act)(() => {
334
+ updateResult = result.current.updateInteractableComponentProps(componentId, undefined);
335
+ });
336
+ expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
337
+ });
338
+ });
339
+ describe("Performance and Efficiency", () => {
340
+ it("should only update changed properties without affecting others", () => {
341
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
342
+ const component = {
343
+ name: "TestComponent",
344
+ description: "A test component",
345
+ component: () => react_2.default.createElement("div", null, "Test"),
346
+ props: {
347
+ title: "Original Title",
348
+ count: 0,
349
+ active: true,
350
+ metadata: { type: "test", version: "1.0" },
351
+ items: ["item1", "item2"],
352
+ },
353
+ propsSchema: zod_1.z.object({
354
+ title: zod_1.z.string(),
355
+ count: zod_1.z.number(),
356
+ active: zod_1.z.boolean(),
357
+ metadata: zod_1.z.object({
358
+ type: zod_1.z.string(),
359
+ version: zod_1.z.string(),
360
+ }),
361
+ items: zod_1.z.array(zod_1.z.string()),
362
+ }),
363
+ };
364
+ let componentId = "";
365
+ (0, react_1.act)(() => {
366
+ componentId = result.current.addInteractableComponent(component);
367
+ });
368
+ const originalProps = result.current.interactableComponents[0].props;
369
+ const originalMetadata = originalProps.metadata;
370
+ const originalItems = originalProps.items;
371
+ // Apply minimal partial update - only change count
372
+ (0, react_1.act)(() => {
373
+ result.current.updateInteractableComponentProps(componentId, {
374
+ count: 1,
375
+ });
376
+ });
377
+ const updatedProps = result.current.interactableComponents[0].props;
378
+ // Verify that only count changed
379
+ expect(updatedProps.count).toBe(1);
380
+ expect(updatedProps.title).toBe("Original Title");
381
+ expect(updatedProps.active).toBe(true);
382
+ // Verify that nested objects are preserved (same reference for efficiency)
383
+ expect(updatedProps.metadata).toBe(originalMetadata);
384
+ expect(updatedProps.items).toBe(originalItems);
385
+ });
386
+ it("should handle large objects efficiently with partial updates", () => {
387
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
388
+ // Create a component with a large initial state
389
+ const largeData = {
390
+ users: Array.from({ length: 1000 }, (_, i) => ({
391
+ id: i,
392
+ name: `User ${i}`,
393
+ })),
394
+ settings: {
395
+ theme: "light",
396
+ language: "en",
397
+ notifications: true,
398
+ privacy: {
399
+ shareData: false,
400
+ analytics: true,
401
+ marketing: false,
402
+ },
403
+ },
404
+ metadata: {
405
+ version: "1.0.0",
406
+ build: "12345",
407
+ timestamp: Date.now(),
408
+ },
409
+ };
410
+ const component = {
411
+ name: "TestComponent",
412
+ description: "A test component with large data",
413
+ component: () => react_2.default.createElement("div", null, "Test"),
414
+ props: largeData,
415
+ propsSchema: zod_1.z.object({
416
+ users: zod_1.z.array(zod_1.z.object({
417
+ id: zod_1.z.number(),
418
+ name: zod_1.z.string(),
419
+ })),
420
+ settings: zod_1.z.object({
421
+ theme: zod_1.z.string(),
422
+ language: zod_1.z.string(),
423
+ notifications: zod_1.z.boolean(),
424
+ privacy: zod_1.z.object({
425
+ shareData: zod_1.z.boolean(),
426
+ analytics: zod_1.z.boolean(),
427
+ marketing: zod_1.z.boolean(),
428
+ }),
429
+ }),
430
+ metadata: zod_1.z.object({
431
+ version: zod_1.z.string(),
432
+ build: zod_1.z.string(),
433
+ timestamp: zod_1.z.number(),
434
+ }),
435
+ }),
436
+ };
437
+ let componentId = "";
438
+ (0, react_1.act)(() => {
439
+ componentId = result.current.addInteractableComponent(component);
440
+ });
441
+ const originalProps = result.current.interactableComponents[0].props;
442
+ const originalUsers = originalProps.users;
443
+ // Apply a small partial update - only change theme (shallow merge behavior)
444
+ (0, react_1.act)(() => {
445
+ result.current.updateInteractableComponentProps(componentId, {
446
+ settings: {
447
+ theme: "dark",
448
+ // Note: other settings properties are not provided, so they will be undefined
449
+ // This demonstrates the shallow merge behavior
450
+ },
451
+ });
452
+ });
453
+ const updatedProps = result.current.interactableComponents[0].props;
454
+ // Verify the update worked
455
+ expect(updatedProps.settings.theme).toBe("dark");
456
+ // Due to shallow merge, other properties are now undefined
457
+ expect(updatedProps.settings.language).toBeUndefined();
458
+ expect(updatedProps.settings.notifications).toBeUndefined();
459
+ // Verify that large arrays are preserved (same reference for efficiency)
460
+ expect(updatedProps.users).toBe(originalUsers);
461
+ // Verify that metadata is preserved (not updated)
462
+ expect(updatedProps.metadata).toBe(originalProps.metadata);
463
+ });
464
+ });
465
+ describe("Edge Cases", () => {
466
+ it("should handle updating a property that doesn't exist in original props", () => {
467
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
468
+ const component = {
469
+ name: "TestComponent",
470
+ description: "A test component",
471
+ component: () => react_2.default.createElement("div", null, "Test"),
472
+ props: {
473
+ title: "Original Title",
474
+ count: 0,
475
+ },
476
+ propsSchema: zod_1.z.object({
477
+ title: zod_1.z.string(),
478
+ count: zod_1.z.number(),
479
+ newProperty: zod_1.z.string().optional(),
480
+ }),
481
+ };
482
+ let componentId = "";
483
+ (0, react_1.act)(() => {
484
+ componentId = result.current.addInteractableComponent(component);
485
+ });
486
+ // Add a new property that wasn't in the original props
487
+ (0, react_1.act)(() => {
488
+ result.current.updateInteractableComponentProps(componentId, {
489
+ newProperty: "New Value",
490
+ });
491
+ });
492
+ expect(result.current.interactableComponents[0].props).toEqual({
493
+ title: "Original Title",
494
+ count: 0,
495
+ newProperty: "New Value",
496
+ });
497
+ });
498
+ it("should handle updating with same values (no-op updates)", () => {
499
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
500
+ const component = {
501
+ name: "TestComponent",
502
+ description: "A test component",
503
+ component: () => react_2.default.createElement("div", null, "Test"),
504
+ props: {
505
+ title: "Original Title",
506
+ count: 5,
507
+ active: true,
508
+ },
509
+ propsSchema: zod_1.z.object({
510
+ title: zod_1.z.string(),
511
+ count: zod_1.z.number(),
512
+ active: zod_1.z.boolean(),
513
+ }),
514
+ };
515
+ let componentId = "";
516
+ (0, react_1.act)(() => {
517
+ componentId = result.current.addInteractableComponent(component);
518
+ });
519
+ const originalProps = result.current.interactableComponents[0].props;
520
+ // Update with the same values
521
+ let updateResult = "";
522
+ (0, react_1.act)(() => {
523
+ updateResult = result.current.updateInteractableComponentProps(componentId, {
524
+ title: "Original Title",
525
+ count: 5,
526
+ active: true,
527
+ });
528
+ });
529
+ expect(updateResult).toBe("Updated successfully");
530
+ expect(result.current.interactableComponents[0].props).toEqual(originalProps);
531
+ });
532
+ it("should handle proper nested partial updates by providing complete nested structure", () => {
533
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
534
+ const component = {
535
+ name: "TestComponent",
536
+ description: "A test component",
537
+ component: () => react_2.default.createElement("div", null, "Test"),
538
+ props: {
539
+ title: "Original Title",
540
+ config: {
541
+ theme: "light",
542
+ language: "en",
543
+ features: {
544
+ notifications: true,
545
+ analytics: false,
546
+ experimental: {
547
+ beta: false,
548
+ alpha: true,
549
+ },
550
+ },
551
+ },
552
+ },
553
+ propsSchema: zod_1.z.object({
554
+ title: zod_1.z.string(),
555
+ config: zod_1.z.object({
556
+ theme: zod_1.z.string(),
557
+ language: zod_1.z.string(),
558
+ features: zod_1.z.object({
559
+ notifications: zod_1.z.boolean(),
560
+ analytics: zod_1.z.boolean(),
561
+ experimental: zod_1.z.object({
562
+ beta: zod_1.z.boolean(),
563
+ alpha: zod_1.z.boolean(),
564
+ }),
565
+ }),
566
+ }),
567
+ }),
568
+ };
569
+ let componentId = "";
570
+ (0, react_1.act)(() => {
571
+ componentId = result.current.addInteractableComponent(component);
572
+ });
573
+ // Proper nested partial update - provide complete nested structure
574
+ (0, react_1.act)(() => {
575
+ result.current.updateInteractableComponentProps(componentId, {
576
+ config: {
577
+ theme: "light", // keep original
578
+ language: "en", // keep original
579
+ features: {
580
+ notifications: true, // keep original
581
+ analytics: false, // keep original
582
+ experimental: {
583
+ beta: true, // update this
584
+ alpha: true, // keep original
585
+ },
586
+ },
587
+ },
588
+ });
589
+ });
590
+ expect(result.current.interactableComponents[0].props).toEqual({
591
+ title: "Original Title",
592
+ config: {
593
+ theme: "light", // unchanged
594
+ language: "en", // unchanged
595
+ features: {
596
+ notifications: true, // unchanged
597
+ analytics: false, // unchanged
598
+ experimental: {
599
+ beta: true, // updated
600
+ alpha: true, // unchanged
601
+ },
602
+ },
603
+ },
604
+ });
605
+ });
606
+ it("should handle complex nested partial updates (shallow merge behavior)", () => {
607
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
608
+ const component = {
609
+ name: "TestComponent",
610
+ description: "A test component",
611
+ component: () => react_2.default.createElement("div", null, "Test"),
612
+ props: {
613
+ title: "Original Title",
614
+ config: {
615
+ theme: "light",
616
+ language: "en",
617
+ features: {
618
+ notifications: true,
619
+ analytics: false,
620
+ experimental: {
621
+ beta: false,
622
+ alpha: true,
623
+ },
624
+ },
625
+ },
626
+ },
627
+ propsSchema: zod_1.z.object({
628
+ title: zod_1.z.string(),
629
+ config: zod_1.z.object({
630
+ theme: zod_1.z.string(),
631
+ language: zod_1.z.string(),
632
+ features: zod_1.z.object({
633
+ notifications: zod_1.z.boolean(),
634
+ analytics: zod_1.z.boolean(),
635
+ experimental: zod_1.z.object({
636
+ beta: zod_1.z.boolean(),
637
+ alpha: zod_1.z.boolean(),
638
+ }),
639
+ }),
640
+ }),
641
+ }),
642
+ };
643
+ let componentId = "";
644
+ (0, react_1.act)(() => {
645
+ componentId = result.current.addInteractableComponent(component);
646
+ });
647
+ // Deep nested partial update - only change beta flag (shallow merge behavior)
648
+ (0, react_1.act)(() => {
649
+ result.current.updateInteractableComponentProps(componentId, {
650
+ config: {
651
+ features: {
652
+ experimental: {
653
+ beta: true,
654
+ // Note: alpha is not provided, so it will be undefined
655
+ // This demonstrates the shallow merge behavior
656
+ },
657
+ },
658
+ },
659
+ });
660
+ });
661
+ expect(result.current.interactableComponents[0].props).toEqual({
662
+ title: "Original Title",
663
+ config: {
664
+ // theme and language are now undefined due to shallow merge
665
+ features: {
666
+ // notifications and analytics are now undefined due to shallow merge
667
+ experimental: {
668
+ beta: true, // updated
669
+ // alpha is now undefined due to shallow merge
670
+ },
671
+ },
672
+ },
673
+ });
674
+ });
675
+ });
676
+ });
677
+ //# sourceMappingURL=tambo-interactable-provider-partial-updates.test.js.map