@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.
- package/dist/hooks/use-tambo-stream-status.js +1 -1
- package/dist/hooks/use-tambo-stream-status.js.map +1 -1
- package/dist/mcp/__tests__/mcp-client.test.js +0 -266
- package/dist/mcp/__tests__/mcp-client.test.js.map +1 -1
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/dist/mcp/__tests__/use-mcp-servers.test.js +34 -9
- package/dist/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
- package/dist/mcp/index.d.ts +3 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +4 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts +12 -79
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +22 -159
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +93 -0
- package/dist/mcp/mcp-hooks.d.ts.map +1 -0
- package/dist/mcp/mcp-hooks.js +56 -0
- package/dist/mcp/mcp-hooks.js.map +1 -0
- package/dist/mcp/tambo-mcp-provider.d.ts +30 -2
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +127 -17
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/model/component-metadata.d.ts +1 -1
- package/dist/model/component-metadata.d.ts.map +1 -1
- package/dist/model/component-metadata.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
- package/dist/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider.test.js +395 -8
- package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/dist/providers/tambo-mcp-token-provider.d.ts +34 -0
- package/dist/providers/tambo-mcp-token-provider.d.ts.map +1 -0
- package/dist/providers/tambo-mcp-token-provider.js +69 -0
- package/dist/providers/tambo-mcp-token-provider.js.map +1 -0
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +7 -5
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js +20 -8
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/testing/tools.d.ts +1 -1
- package/esm/hooks/use-tambo-stream-status.js +1 -1
- package/esm/hooks/use-tambo-stream-status.js.map +1 -1
- package/esm/mcp/__tests__/mcp-client.test.js +0 -266
- package/esm/mcp/__tests__/mcp-client.test.js.map +1 -1
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js +218 -12
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/esm/mcp/__tests__/use-mcp-servers.test.js +34 -9
- package/esm/mcp/__tests__/use-mcp-servers.test.js.map +1 -1
- package/esm/mcp/index.d.ts +3 -1
- package/esm/mcp/index.d.ts.map +1 -1
- package/esm/mcp/index.js +1 -0
- package/esm/mcp/index.js.map +1 -1
- package/esm/mcp/mcp-client.d.ts +12 -79
- package/esm/mcp/mcp-client.d.ts.map +1 -1
- package/esm/mcp/mcp-client.js +22 -159
- package/esm/mcp/mcp-client.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +93 -0
- package/esm/mcp/mcp-hooks.d.ts.map +1 -0
- package/esm/mcp/mcp-hooks.js +52 -0
- package/esm/mcp/mcp-hooks.js.map +1 -0
- package/esm/mcp/tambo-mcp-provider.d.ts +30 -2
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +128 -18
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/model/component-metadata.d.ts +1 -1
- package/esm/model/component-metadata.d.ts.map +1 -1
- package/esm/model/component-metadata.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js +3 -1
- package/esm/providers/__tests__/tambo-thread-provider-initial-messages.test.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider.test.js +395 -8
- package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/esm/providers/tambo-mcp-token-provider.d.ts +34 -0
- package/esm/providers/tambo-mcp-token-provider.d.ts.map +1 -0
- package/esm/providers/tambo-mcp-token-provider.js +31 -0
- package/esm/providers/tambo-mcp-token-provider.js.map +1 -0
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +7 -5
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js +20 -8
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/testing/tools.d.ts +1 -1
- 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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|