@tambo-ai/react 0.58.0 → 0.59.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 (85) hide show
  1. package/dist/hooks/use-tambo-stream-status.js +1 -1
  2. package/dist/hooks/use-tambo-stream-status.js.map +1 -1
  3. package/dist/mcp/__tests__/mcp-client.test.js +0 -266
  4. package/dist/mcp/__tests__/mcp-client.test.js.map +1 -1
  5. package/dist/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
  6. package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
  7. package/dist/mcp/__tests__/use-mcp-servers.test.js +34 -9
  8. package/dist/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
  9. package/dist/mcp/index.d.ts +3 -1
  10. package/dist/mcp/index.d.ts.map +1 -1
  11. package/dist/mcp/index.js +4 -1
  12. package/dist/mcp/index.js.map +1 -1
  13. package/dist/mcp/mcp-client.d.ts +12 -79
  14. package/dist/mcp/mcp-client.d.ts.map +1 -1
  15. package/dist/mcp/mcp-client.js +22 -159
  16. package/dist/mcp/mcp-client.js.map +1 -1
  17. package/dist/mcp/mcp-hooks.d.ts +93 -0
  18. package/dist/mcp/mcp-hooks.d.ts.map +1 -0
  19. package/dist/mcp/mcp-hooks.js +56 -0
  20. package/dist/mcp/mcp-hooks.js.map +1 -0
  21. package/dist/mcp/tambo-mcp-provider.d.ts +30 -2
  22. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  23. package/dist/mcp/tambo-mcp-provider.js +127 -17
  24. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  25. package/dist/model/component-metadata.d.ts +1 -1
  26. package/dist/model/component-metadata.d.ts.map +1 -1
  27. package/dist/model/component-metadata.js.map +1 -1
  28. package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
  29. package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
  30. package/dist/providers/__tests__/tambo-thread-provider.test.js +395 -8
  31. package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  32. package/dist/providers/tambo-mcp-token-provider.d.ts +34 -0
  33. package/dist/providers/tambo-mcp-token-provider.d.ts.map +1 -0
  34. package/dist/providers/tambo-mcp-token-provider.js +69 -0
  35. package/dist/providers/tambo-mcp-token-provider.js.map +1 -0
  36. package/dist/providers/tambo-provider.d.ts.map +1 -1
  37. package/dist/providers/tambo-provider.js +7 -5
  38. package/dist/providers/tambo-provider.js.map +1 -1
  39. package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
  40. package/dist/providers/tambo-thread-provider.js +20 -8
  41. package/dist/providers/tambo-thread-provider.js.map +1 -1
  42. package/dist/testing/tools.d.ts +1 -1
  43. package/esm/hooks/use-tambo-stream-status.js +1 -1
  44. package/esm/hooks/use-tambo-stream-status.js.map +1 -1
  45. package/esm/mcp/__tests__/mcp-client.test.js +0 -266
  46. package/esm/mcp/__tests__/mcp-client.test.js.map +1 -1
  47. package/esm/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
  48. package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
  49. package/esm/mcp/__tests__/use-mcp-servers.test.js +34 -9
  50. package/esm/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
  51. package/esm/mcp/index.d.ts +3 -1
  52. package/esm/mcp/index.d.ts.map +1 -1
  53. package/esm/mcp/index.js +1 -0
  54. package/esm/mcp/index.js.map +1 -1
  55. package/esm/mcp/mcp-client.d.ts +12 -79
  56. package/esm/mcp/mcp-client.d.ts.map +1 -1
  57. package/esm/mcp/mcp-client.js +22 -159
  58. package/esm/mcp/mcp-client.js.map +1 -1
  59. package/esm/mcp/mcp-hooks.d.ts +93 -0
  60. package/esm/mcp/mcp-hooks.d.ts.map +1 -0
  61. package/esm/mcp/mcp-hooks.js +52 -0
  62. package/esm/mcp/mcp-hooks.js.map +1 -0
  63. package/esm/mcp/tambo-mcp-provider.d.ts +30 -2
  64. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  65. package/esm/mcp/tambo-mcp-provider.js +128 -18
  66. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  67. package/esm/model/component-metadata.d.ts +1 -1
  68. package/esm/model/component-metadata.d.ts.map +1 -1
  69. package/esm/model/component-metadata.js.map +1 -1
  70. package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
  71. package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
  72. package/esm/providers/__tests__/tambo-thread-provider.test.js +395 -8
  73. package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
  74. package/esm/providers/tambo-mcp-token-provider.d.ts +34 -0
  75. package/esm/providers/tambo-mcp-token-provider.d.ts.map +1 -0
  76. package/esm/providers/tambo-mcp-token-provider.js +31 -0
  77. package/esm/providers/tambo-mcp-token-provider.js.map +1 -0
  78. package/esm/providers/tambo-provider.d.ts.map +1 -1
  79. package/esm/providers/tambo-provider.js +7 -5
  80. package/esm/providers/tambo-provider.js.map +1 -1
  81. package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
  82. package/esm/providers/tambo-thread-provider.js +20 -8
  83. package/esm/providers/tambo-thread-provider.js.map +1 -1
  84. package/esm/testing/tools.d.ts +1 -1
  85. package/package.json +1 -1
@@ -11,6 +11,7 @@ const generate_component_response_1 = require("../../model/generate-component-re
11
11
  const tools_1 = require("../../testing/tools");
12
12
  const tambo_client_provider_1 = require("../tambo-client-provider");
13
13
  const tambo_context_helpers_provider_1 = require("../tambo-context-helpers-provider");
14
+ const tambo_mcp_token_provider_1 = require("../tambo-mcp-token-provider");
14
15
  const tambo_registry_provider_1 = require("../tambo-registry-provider");
15
16
  const tambo_thread_provider_1 = require("../tambo-thread-provider");
16
17
  // Mock crypto.randomUUID
@@ -116,7 +117,8 @@ describe("TamboThreadProvider", () => {
116
117
  currentTimeContextHelper: () => null,
117
118
  currentPageContextHelper: () => null,
118
119
  } },
119
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children))));
120
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
121
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
120
122
  beforeEach(() => {
121
123
  jest.clearAllMocks();
122
124
  // Setup mock query client
@@ -332,7 +334,8 @@ describe("TamboThreadProvider", () => {
332
334
  currentTimeContextHelper: () => null,
333
335
  currentPageContextHelper: () => null,
334
336
  } },
335
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children))));
337
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
338
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
336
339
  const mockUnregisteredToolCallResponse = {
337
340
  responseMessageDto: {
338
341
  id: "unregistered-tool-call-1",
@@ -430,7 +433,8 @@ describe("TamboThreadProvider", () => {
430
433
  currentTimeContextHelper: () => null,
431
434
  currentPageContextHelper: () => null,
432
435
  } },
433
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children))));
436
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
437
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children)))));
434
438
  const mockStreamResponse = {
435
439
  responseMessageDto: {
436
440
  id: "stream-response",
@@ -491,7 +495,8 @@ describe("TamboThreadProvider", () => {
491
495
  currentTimeContextHelper: () => null,
492
496
  currentPageContextHelper: () => null,
493
497
  } },
494
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children))));
498
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
499
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children)))));
495
500
  const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
496
501
  wrapper: wrapperWithStreaming,
497
502
  });
@@ -533,7 +538,8 @@ describe("TamboThreadProvider", () => {
533
538
  currentTimeContextHelper: () => null,
534
539
  currentPageContextHelper: () => null,
535
540
  } },
536
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children))));
541
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
542
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
537
543
  const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
538
544
  wrapper: wrapperWithoutStreaming,
539
545
  });
@@ -575,7 +581,8 @@ describe("TamboThreadProvider", () => {
575
581
  currentTimeContextHelper: () => null,
576
582
  currentPageContextHelper: () => null,
577
583
  } },
578
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, null, children))));
584
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
585
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, null, children)))));
579
586
  const mockStreamResponse = {
580
587
  responseMessageDto: {
581
588
  id: "stream-response",
@@ -636,7 +643,8 @@ describe("TamboThreadProvider", () => {
636
643
  currentTimeContextHelper: () => null,
637
644
  currentPageContextHelper: () => null,
638
645
  } },
639
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children))));
646
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
647
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children)))));
640
648
  const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
641
649
  wrapper: wrapperWithStreaming,
642
650
  });
@@ -680,7 +688,8 @@ describe("TamboThreadProvider", () => {
680
688
  currentTimeContextHelper: () => null,
681
689
  currentPageContextHelper: () => null,
682
690
  } },
683
- react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children))));
691
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
692
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
684
693
  const mockStreamResponse = {
685
694
  responseMessageDto: {
686
695
  id: "stream-response",
@@ -849,5 +858,383 @@ describe("TamboThreadProvider", () => {
849
858
  expect(result.current.thread.id).toBe("existing-thread-123");
850
859
  });
851
860
  });
861
+ describe("transformToContent", () => {
862
+ it("should use custom transformToContent when provided (non-streaming)", async () => {
863
+ const mockTransformToContent = jest.fn().mockReturnValue([
864
+ { type: "text", text: "Custom transformed content" },
865
+ {
866
+ type: "image_url",
867
+ image_url: { url: "https://example.com/image.png" },
868
+ },
869
+ ]);
870
+ const customToolRegistry = [
871
+ {
872
+ name: "TestComponent",
873
+ component: () => react_2.default.createElement("div", null, "Test"),
874
+ description: "Test",
875
+ propsSchema: zod_1.z.object({ test: zod_1.z.string() }),
876
+ associatedTools: [
877
+ {
878
+ name: "custom-tool",
879
+ tool: jest.fn().mockResolvedValue({ data: "tool result" }),
880
+ description: "Tool with custom transform",
881
+ toolSchema: zod_1.z
882
+ .function()
883
+ .args(zod_1.z.string())
884
+ .returns(zod_1.z.object({ data: zod_1.z.string() })),
885
+ transformToContent: mockTransformToContent,
886
+ },
887
+ ],
888
+ },
889
+ ];
890
+ const wrapperWithCustomTool = ({ children, }) => (react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, { components: customToolRegistry },
891
+ react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, { contextHelpers: {
892
+ currentTimeContextHelper: () => null,
893
+ currentPageContextHelper: () => null,
894
+ } },
895
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
896
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
897
+ const mockToolCallResponse = {
898
+ responseMessageDto: {
899
+ id: "tool-call-1",
900
+ content: [{ type: "text", text: "Tool response" }],
901
+ role: "tool",
902
+ threadId: "test-thread-1",
903
+ toolCallRequest: {
904
+ toolName: "custom-tool",
905
+ parameters: [{ parameterName: "input", parameterValue: "test" }],
906
+ },
907
+ componentState: {},
908
+ createdAt: new Date().toISOString(),
909
+ },
910
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
911
+ mcpAccessToken: "test-mcp-access-token",
912
+ };
913
+ jest
914
+ .mocked(mockThreadsApi.advanceByID)
915
+ .mockResolvedValueOnce(mockToolCallResponse)
916
+ .mockResolvedValueOnce({
917
+ responseMessageDto: {
918
+ id: "final-response",
919
+ content: [{ type: "text", text: "Final response" }],
920
+ role: "assistant",
921
+ threadId: "test-thread-1",
922
+ componentState: {},
923
+ createdAt: new Date().toISOString(),
924
+ },
925
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
926
+ mcpAccessToken: "test-mcp-access-token",
927
+ });
928
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
929
+ wrapper: wrapperWithCustomTool,
930
+ });
931
+ await (0, react_1.act)(async () => {
932
+ await result.current.sendThreadMessage("Use custom tool", {
933
+ threadId: "test-thread-1",
934
+ streamResponse: false,
935
+ });
936
+ });
937
+ // Verify the tool was called
938
+ expect(customToolRegistry[0]?.associatedTools?.[0]?.tool).toHaveBeenCalledWith("test");
939
+ // Verify transformToContent was called with the tool result
940
+ expect(mockTransformToContent).toHaveBeenCalledWith({
941
+ data: "tool result",
942
+ });
943
+ // Verify the second advance call included the transformed content
944
+ expect(mockThreadsApi.advanceByID).toHaveBeenCalledTimes(2);
945
+ expect(mockThreadsApi.advanceByID).toHaveBeenLastCalledWith("test-thread-1", expect.objectContaining({
946
+ messageToAppend: expect.objectContaining({
947
+ content: [
948
+ { type: "text", text: "Custom transformed content" },
949
+ {
950
+ type: "image_url",
951
+ image_url: { url: "https://example.com/image.png" },
952
+ },
953
+ ],
954
+ role: "tool",
955
+ }),
956
+ }));
957
+ });
958
+ it("should use custom async transformToContent when provided (streaming)", async () => {
959
+ const mockTransformToContent = jest
960
+ .fn()
961
+ .mockResolvedValue([
962
+ { type: "text", text: "Async transformed content" },
963
+ ]);
964
+ const customToolRegistry = [
965
+ {
966
+ name: "TestComponent",
967
+ component: () => react_2.default.createElement("div", null, "Test"),
968
+ description: "Test",
969
+ propsSchema: zod_1.z.object({ test: zod_1.z.string() }),
970
+ associatedTools: [
971
+ {
972
+ name: "async-tool",
973
+ tool: jest.fn().mockResolvedValue({ data: "async tool result" }),
974
+ description: "Tool with async transform",
975
+ toolSchema: zod_1.z
976
+ .function()
977
+ .args(zod_1.z.string())
978
+ .returns(zod_1.z.object({ data: zod_1.z.string() })),
979
+ transformToContent: mockTransformToContent,
980
+ },
981
+ ],
982
+ },
983
+ ];
984
+ const wrapperWithAsyncTool = ({ children, }) => (react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, { components: customToolRegistry },
985
+ react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, { contextHelpers: {
986
+ currentTimeContextHelper: () => null,
987
+ currentPageContextHelper: () => null,
988
+ } },
989
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
990
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: true }, children)))));
991
+ const mockToolCallChunk = {
992
+ responseMessageDto: {
993
+ id: "tool-call-chunk",
994
+ content: [{ type: "text", text: "Tool call" }],
995
+ role: "tool",
996
+ threadId: "test-thread-1",
997
+ toolCallRequest: {
998
+ toolName: "async-tool",
999
+ parameters: [
1000
+ { parameterName: "input", parameterValue: "async-test" },
1001
+ ],
1002
+ },
1003
+ componentState: {},
1004
+ createdAt: new Date().toISOString(),
1005
+ },
1006
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1007
+ mcpAccessToken: "test-mcp-access-token",
1008
+ };
1009
+ const mockFinalChunk = {
1010
+ responseMessageDto: {
1011
+ id: "final-chunk",
1012
+ content: [{ type: "text", text: "Final streaming response" }],
1013
+ role: "assistant",
1014
+ threadId: "test-thread-1",
1015
+ componentState: {},
1016
+ createdAt: new Date().toISOString(),
1017
+ },
1018
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1019
+ mcpAccessToken: "test-mcp-access-token",
1020
+ };
1021
+ const mockAsyncIterator = {
1022
+ [Symbol.asyncIterator]: async function* () {
1023
+ yield mockToolCallChunk;
1024
+ yield mockFinalChunk;
1025
+ },
1026
+ };
1027
+ jest
1028
+ .mocked(typescript_sdk_1.advanceStream)
1029
+ .mockResolvedValueOnce(mockAsyncIterator)
1030
+ .mockResolvedValueOnce({
1031
+ [Symbol.asyncIterator]: async function* () {
1032
+ yield mockFinalChunk;
1033
+ },
1034
+ });
1035
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
1036
+ wrapper: wrapperWithAsyncTool,
1037
+ });
1038
+ await (0, react_1.act)(async () => {
1039
+ await result.current.sendThreadMessage("Use async tool", {
1040
+ threadId: "test-thread-1",
1041
+ streamResponse: true,
1042
+ });
1043
+ });
1044
+ // Verify the tool was called
1045
+ expect(customToolRegistry[0]?.associatedTools?.[0]?.tool).toHaveBeenCalledWith("async-test");
1046
+ // Verify transformToContent was called
1047
+ expect(mockTransformToContent).toHaveBeenCalledWith({
1048
+ data: "async tool result",
1049
+ });
1050
+ // Verify advanceStream was called twice (initial request and tool response)
1051
+ expect(typescript_sdk_1.advanceStream).toHaveBeenCalledTimes(2);
1052
+ // Verify the second advanceStream call included the transformed content
1053
+ expect(typescript_sdk_1.advanceStream).toHaveBeenLastCalledWith(mockTamboAI, expect.objectContaining({
1054
+ messageToAppend: expect.objectContaining({
1055
+ content: [{ type: "text", text: "Async transformed content" }],
1056
+ role: "tool",
1057
+ }),
1058
+ }), "test-thread-1");
1059
+ });
1060
+ it("should fallback to stringified text when transformToContent is not provided", async () => {
1061
+ const toolWithoutTransform = [
1062
+ {
1063
+ name: "TestComponent",
1064
+ component: () => react_2.default.createElement("div", null, "Test"),
1065
+ description: "Test",
1066
+ propsSchema: zod_1.z.object({ test: zod_1.z.string() }),
1067
+ associatedTools: [
1068
+ {
1069
+ name: "no-transform-tool",
1070
+ tool: jest
1071
+ .fn()
1072
+ .mockResolvedValue({ complex: "data", nested: { value: 42 } }),
1073
+ description: "Tool without custom transform",
1074
+ toolSchema: zod_1.z
1075
+ .function()
1076
+ .args(zod_1.z.string())
1077
+ .returns(zod_1.z.object({
1078
+ complex: zod_1.z.string(),
1079
+ nested: zod_1.z.object({ value: zod_1.z.number() }),
1080
+ })),
1081
+ // No transformToContent provided
1082
+ },
1083
+ ],
1084
+ },
1085
+ ];
1086
+ const wrapperWithoutTransform = ({ children, }) => (react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, { components: toolWithoutTransform },
1087
+ react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, { contextHelpers: {
1088
+ currentTimeContextHelper: () => null,
1089
+ currentPageContextHelper: () => null,
1090
+ } },
1091
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
1092
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
1093
+ const mockToolCallResponse = {
1094
+ responseMessageDto: {
1095
+ id: "tool-call-1",
1096
+ content: [{ type: "text", text: "Tool call" }],
1097
+ role: "tool",
1098
+ threadId: "test-thread-1",
1099
+ toolCallRequest: {
1100
+ toolName: "no-transform-tool",
1101
+ parameters: [{ parameterName: "input", parameterValue: "test" }],
1102
+ },
1103
+ componentState: {},
1104
+ createdAt: new Date().toISOString(),
1105
+ },
1106
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1107
+ mcpAccessToken: "test-mcp-access-token",
1108
+ };
1109
+ jest
1110
+ .mocked(mockThreadsApi.advanceByID)
1111
+ .mockResolvedValueOnce(mockToolCallResponse)
1112
+ .mockResolvedValueOnce({
1113
+ responseMessageDto: {
1114
+ id: "final-response",
1115
+ content: [{ type: "text", text: "Final response" }],
1116
+ role: "assistant",
1117
+ threadId: "test-thread-1",
1118
+ componentState: {},
1119
+ createdAt: new Date().toISOString(),
1120
+ },
1121
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1122
+ mcpAccessToken: "test-mcp-access-token",
1123
+ });
1124
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
1125
+ wrapper: wrapperWithoutTransform,
1126
+ });
1127
+ await (0, react_1.act)(async () => {
1128
+ await result.current.sendThreadMessage("Use tool without transform", {
1129
+ threadId: "test-thread-1",
1130
+ streamResponse: false,
1131
+ });
1132
+ });
1133
+ // Verify the tool was called
1134
+ expect(toolWithoutTransform[0]?.associatedTools?.[0]?.tool).toHaveBeenCalledWith("test");
1135
+ // Verify the second advance call used stringified content
1136
+ expect(mockThreadsApi.advanceByID).toHaveBeenLastCalledWith("test-thread-1", expect.objectContaining({
1137
+ messageToAppend: expect.objectContaining({
1138
+ content: [
1139
+ {
1140
+ type: "text",
1141
+ text: '{"complex":"data","nested":{"value":42}}',
1142
+ },
1143
+ ],
1144
+ role: "tool",
1145
+ }),
1146
+ }));
1147
+ });
1148
+ it("should always return text for error responses even with transformToContent", async () => {
1149
+ const mockTransformToContent = jest.fn().mockReturnValue([
1150
+ {
1151
+ type: "image_url",
1152
+ image_url: { url: "https://example.com/error.png" },
1153
+ },
1154
+ ]);
1155
+ const toolWithTransform = [
1156
+ {
1157
+ name: "TestComponent",
1158
+ component: () => react_2.default.createElement("div", null, "Test"),
1159
+ description: "Test",
1160
+ propsSchema: zod_1.z.object({ test: zod_1.z.string() }),
1161
+ associatedTools: [
1162
+ {
1163
+ name: "error-tool",
1164
+ tool: jest
1165
+ .fn()
1166
+ .mockRejectedValue(new Error("Tool execution failed")),
1167
+ description: "Tool that errors",
1168
+ toolSchema: zod_1.z.function().args(zod_1.z.string()).returns(zod_1.z.string()),
1169
+ transformToContent: mockTransformToContent,
1170
+ },
1171
+ ],
1172
+ },
1173
+ ];
1174
+ const wrapperWithErrorTool = ({ children, }) => (react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, { components: toolWithTransform },
1175
+ react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, { contextHelpers: {
1176
+ currentTimeContextHelper: () => null,
1177
+ currentPageContextHelper: () => null,
1178
+ } },
1179
+ react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
1180
+ react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { streaming: false }, children)))));
1181
+ const mockToolCallResponse = {
1182
+ responseMessageDto: {
1183
+ id: "tool-call-1",
1184
+ content: [{ type: "text", text: "Tool call" }],
1185
+ role: "tool",
1186
+ threadId: "test-thread-1",
1187
+ toolCallRequest: {
1188
+ toolName: "error-tool",
1189
+ parameters: [{ parameterName: "input", parameterValue: "test" }],
1190
+ },
1191
+ componentState: {},
1192
+ createdAt: new Date().toISOString(),
1193
+ },
1194
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1195
+ mcpAccessToken: "test-mcp-access-token",
1196
+ };
1197
+ jest
1198
+ .mocked(mockThreadsApi.advanceByID)
1199
+ .mockResolvedValueOnce(mockToolCallResponse)
1200
+ .mockResolvedValueOnce({
1201
+ responseMessageDto: {
1202
+ id: "final-response",
1203
+ content: [{ type: "text", text: "Final response" }],
1204
+ role: "assistant",
1205
+ threadId: "test-thread-1",
1206
+ componentState: {},
1207
+ createdAt: new Date().toISOString(),
1208
+ },
1209
+ generationStage: generate_component_response_1.GenerationStage.COMPLETE,
1210
+ mcpAccessToken: "test-mcp-access-token",
1211
+ });
1212
+ const { result } = (0, react_1.renderHook)(() => (0, tambo_thread_provider_1.useTamboThread)(), {
1213
+ wrapper: wrapperWithErrorTool,
1214
+ });
1215
+ await (0, react_1.act)(async () => {
1216
+ await result.current.sendThreadMessage("Use error tool", {
1217
+ threadId: "test-thread-1",
1218
+ streamResponse: false,
1219
+ });
1220
+ });
1221
+ // Verify the tool was called
1222
+ expect(toolWithTransform[0]?.associatedTools?.[0]?.tool).toHaveBeenCalledWith("test");
1223
+ // Verify transformToContent was NOT called for error responses
1224
+ expect(mockTransformToContent).not.toHaveBeenCalled();
1225
+ // Verify the second advance call used text content with the error message
1226
+ expect(mockThreadsApi.advanceByID).toHaveBeenLastCalledWith("test-thread-1", expect.objectContaining({
1227
+ messageToAppend: expect.objectContaining({
1228
+ content: [
1229
+ expect.objectContaining({
1230
+ type: "text",
1231
+ // Error message should be in text format
1232
+ }),
1233
+ ],
1234
+ role: "tool",
1235
+ }),
1236
+ }));
1237
+ });
1238
+ });
852
1239
  });
853
1240
  //# sourceMappingURL=tambo-thread-provider.test.js.map