@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { FC } from "react";
|
|
2
|
-
import { MCPClient, MCPTransport } from "./mcp-client";
|
|
2
|
+
import { MCPClient, MCPHandlers, MCPTransport } from "./mcp-client";
|
|
3
3
|
/**
|
|
4
4
|
* Extracts error message from MCP tool result content.
|
|
5
5
|
* Handles both array and string content formats.
|
|
@@ -7,12 +7,26 @@ import { MCPClient, MCPTransport } from "./mcp-client";
|
|
|
7
7
|
* @returns The extracted error message as a string
|
|
8
8
|
*/
|
|
9
9
|
export declare function extractErrorMessage(content: unknown): string;
|
|
10
|
+
/**
|
|
11
|
+
* Configuration for connecting to an MCP server.
|
|
12
|
+
*/
|
|
10
13
|
export interface McpServerInfo {
|
|
14
|
+
/** Optional name for the MCP server */
|
|
11
15
|
name?: string;
|
|
16
|
+
/** The URL of the MCP server to connect to */
|
|
12
17
|
url: string;
|
|
18
|
+
/** Optional description of the MCP server */
|
|
13
19
|
description?: string;
|
|
20
|
+
/** The transport type to use (SSE or HTTP). Defaults to SSE for string URLs */
|
|
14
21
|
transport?: MCPTransport;
|
|
22
|
+
/** Optional custom headers to include in requests */
|
|
15
23
|
customHeaders?: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* Optional handlers for elicitation and sampling requests from the server.
|
|
26
|
+
* Note: These callbacks should be stable (e.g., wrapped in useCallback or defined outside the component)
|
|
27
|
+
* to avoid constant re-registration of the MCP server on every render.
|
|
28
|
+
*/
|
|
29
|
+
handlers?: Partial<MCPHandlers>;
|
|
16
30
|
}
|
|
17
31
|
export interface ConnectedMcpServer extends McpServerInfo {
|
|
18
32
|
client: MCPClient;
|
|
@@ -22,12 +36,26 @@ export interface FailedMcpServer extends McpServerInfo {
|
|
|
22
36
|
connectionError: Error;
|
|
23
37
|
}
|
|
24
38
|
export type McpServer = ConnectedMcpServer | FailedMcpServer;
|
|
39
|
+
/**
|
|
40
|
+
* Provider-level MCP handlers that receive the McpServerInfo as context in addition to the request.
|
|
41
|
+
* These handlers are applied to all MCP servers unless overridden by per-server handlers.
|
|
42
|
+
*/
|
|
43
|
+
export interface ProviderMCPHandlers {
|
|
44
|
+
elicitation?: (request: Parameters<MCPHandlers["elicitation"]>[0], serverInfo: McpServerInfo) => ReturnType<MCPHandlers["elicitation"]>;
|
|
45
|
+
sampling?: (request: Parameters<MCPHandlers["sampling"]>[0], serverInfo: McpServerInfo) => ReturnType<MCPHandlers["sampling"]>;
|
|
46
|
+
}
|
|
25
47
|
/**
|
|
26
48
|
* This provider is used to register tools from MCP servers.
|
|
27
|
-
*
|
|
49
|
+
* It automatically includes an internal Tambo MCP server when an MCP access token is available.
|
|
50
|
+
* @param props - The provider props
|
|
51
|
+
* @param props.mcpServers - Array of MCP server configurations
|
|
52
|
+
* @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server
|
|
53
|
+
* @param props.children - The children to wrap
|
|
54
|
+
* @returns The TamboMcpProvider component
|
|
28
55
|
*/
|
|
29
56
|
export declare const TamboMcpProvider: FC<{
|
|
30
57
|
mcpServers: (McpServerInfo | string)[];
|
|
58
|
+
handlers?: ProviderMCPHandlers;
|
|
31
59
|
children: React.ReactNode;
|
|
32
60
|
}>;
|
|
33
61
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-mcp-provider.d.ts","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,EAAE,
|
|
1
|
+
{"version":3,"file":"tambo-mcp-provider.d.ts","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAEZ,EAAE,EAKH,MAAM,OAAO,CAAC;AAKf,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAsB5D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,eAAe,EAAE,KAAK,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAClD,UAAU,EAAE,aAAa,KACtB,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CACT,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAC/C,UAAU,EAAE,aAAa,KACtB,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;CAC1C;AAOD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC;IAChC,UAAU,EAAE,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CA8QA,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,kBAAkB,mBAE9B,CAAC"}
|
|
@@ -37,8 +37,9 @@ exports.useTamboMcpServers = exports.TamboMcpProvider = void 0;
|
|
|
37
37
|
exports.extractErrorMessage = extractErrorMessage;
|
|
38
38
|
const fast_equals_1 = require("fast-equals");
|
|
39
39
|
const react_1 = __importStar(require("react"));
|
|
40
|
-
const
|
|
40
|
+
const tambo_mcp_token_provider_1 = require("../providers/tambo-mcp-token-provider");
|
|
41
41
|
const tambo_registry_provider_1 = require("../providers/tambo-registry-provider");
|
|
42
|
+
const content_parts_1 = require("../util/content-parts");
|
|
42
43
|
const mcp_client_1 = require("./mcp-client");
|
|
43
44
|
/**
|
|
44
45
|
* Extracts error message from MCP tool result content.
|
|
@@ -64,15 +65,45 @@ function extractErrorMessage(content) {
|
|
|
64
65
|
return `${content}`;
|
|
65
66
|
}
|
|
66
67
|
const McpProviderContext = (0, react_1.createContext)([]);
|
|
68
|
+
// Constant for the internal Tambo MCP server name
|
|
69
|
+
const TAMBO_INTERNAL_MCP_SERVER_NAME = "__tambo_internal_mcp_server__";
|
|
67
70
|
/**
|
|
68
71
|
* This provider is used to register tools from MCP servers.
|
|
69
|
-
*
|
|
72
|
+
* It automatically includes an internal Tambo MCP server when an MCP access token is available.
|
|
73
|
+
* @param props - The provider props
|
|
74
|
+
* @param props.mcpServers - Array of MCP server configurations
|
|
75
|
+
* @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server
|
|
76
|
+
* @param props.children - The children to wrap
|
|
77
|
+
* @returns The TamboMcpProvider component
|
|
70
78
|
*/
|
|
71
|
-
const TamboMcpProvider = ({ mcpServers, children }) => {
|
|
79
|
+
const TamboMcpProvider = ({ mcpServers, handlers, children }) => {
|
|
72
80
|
const { registerTool } = (0, tambo_registry_provider_1.useTamboRegistry)();
|
|
81
|
+
const { mcpAccessToken, tamboBaseUrl } = (0, tambo_mcp_token_provider_1.useTamboMcpToken)();
|
|
82
|
+
const providerElicitationHandler = handlers?.elicitation;
|
|
83
|
+
const providerSamplingHandler = handlers?.sampling;
|
|
73
84
|
const [connectedMcpServers, setConnectedMcpServers] = (0, react_1.useState)([]);
|
|
85
|
+
// Combine user-provided MCP servers with the internal Tambo MCP server
|
|
86
|
+
const allMcpServers = (0, react_1.useMemo)(() => {
|
|
87
|
+
const servers = [...mcpServers];
|
|
88
|
+
// Add internal Tambo MCP server if we have an access token and a base URL
|
|
89
|
+
if (mcpAccessToken && tamboBaseUrl) {
|
|
90
|
+
// Build the internal MCP URL robustly, preserving any existing base path
|
|
91
|
+
const base = new URL(tamboBaseUrl);
|
|
92
|
+
base.pathname = `${base.pathname.replace(/\/+$/, "")}/mcp`;
|
|
93
|
+
const tamboMcpUrl = base.toString();
|
|
94
|
+
servers.push({
|
|
95
|
+
name: TAMBO_INTERNAL_MCP_SERVER_NAME,
|
|
96
|
+
url: tamboMcpUrl,
|
|
97
|
+
transport: mcp_client_1.MCPTransport.HTTP,
|
|
98
|
+
customHeaders: {
|
|
99
|
+
Authorization: `Bearer ${mcpAccessToken}`,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return servers;
|
|
104
|
+
}, [mcpServers, mcpAccessToken, tamboBaseUrl]);
|
|
74
105
|
(0, react_1.useEffect)(() => {
|
|
75
|
-
if (!
|
|
106
|
+
if (!allMcpServers.length) {
|
|
76
107
|
return;
|
|
77
108
|
}
|
|
78
109
|
async function registerMcpServers(mcpServerInfos) {
|
|
@@ -84,19 +115,48 @@ const TamboMcpProvider = ({ mcpServers, children }) => {
|
|
|
84
115
|
// initialize the MCP clients, converting McpServerInfo -> McpServer
|
|
85
116
|
const mcpServers = await Promise.allSettled(mcpServerInfos.map(async (mcpServerInfo) => {
|
|
86
117
|
try {
|
|
118
|
+
// Merge provider handlers with per-server handlers (per-server takes precedence)
|
|
119
|
+
const effectiveHandlers = {};
|
|
120
|
+
// Apply provider elicitation handler if present and not overridden
|
|
121
|
+
if (mcpServerInfo.handlers?.elicitation) {
|
|
122
|
+
effectiveHandlers.elicitation =
|
|
123
|
+
mcpServerInfo.handlers.elicitation;
|
|
124
|
+
}
|
|
125
|
+
else if (providerElicitationHandler) {
|
|
126
|
+
const elicitationHandler = providerElicitationHandler;
|
|
127
|
+
effectiveHandlers.elicitation = async (request) => await elicitationHandler(request, mcpServerInfo);
|
|
128
|
+
}
|
|
129
|
+
// Apply provider sampling handler if present and not overridden
|
|
130
|
+
if (mcpServerInfo.handlers?.sampling) {
|
|
131
|
+
effectiveHandlers.sampling = mcpServerInfo.handlers.sampling;
|
|
132
|
+
}
|
|
133
|
+
else if (providerSamplingHandler) {
|
|
134
|
+
const samplingHandler = providerSamplingHandler;
|
|
135
|
+
effectiveHandlers.sampling = async (request) => await samplingHandler(request, mcpServerInfo);
|
|
136
|
+
}
|
|
87
137
|
const client = await mcp_client_1.MCPClient.create(mcpServerInfo.url, mcpServerInfo.transport, mcpServerInfo.customHeaders, undefined, // no oauth support yet
|
|
88
|
-
undefined
|
|
138
|
+
undefined, // starting with no session id at first.
|
|
139
|
+
effectiveHandlers);
|
|
89
140
|
const connectedMcpServer = {
|
|
90
141
|
...mcpServerInfo,
|
|
91
142
|
client: client,
|
|
92
143
|
};
|
|
93
144
|
// note because the promises may resolve in any order, the resulting
|
|
94
145
|
// array may not be in the same order as the input array
|
|
95
|
-
setConnectedMcpServers((prev) =>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
146
|
+
setConnectedMcpServers((prev) => {
|
|
147
|
+
const existing = prev.find((s) => equalsMcpServer(s, mcpServerInfo));
|
|
148
|
+
try {
|
|
149
|
+
existing?.client?.close();
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// best-effort cleanup
|
|
153
|
+
}
|
|
154
|
+
return [
|
|
155
|
+
// replace the server if it already exists
|
|
156
|
+
...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
|
|
157
|
+
connectedMcpServer,
|
|
158
|
+
];
|
|
159
|
+
});
|
|
100
160
|
return connectedMcpServer;
|
|
101
161
|
}
|
|
102
162
|
catch (error) {
|
|
@@ -106,11 +166,20 @@ const TamboMcpProvider = ({ mcpServers, children }) => {
|
|
|
106
166
|
};
|
|
107
167
|
// note because the promises may resolve in any order, the resulting
|
|
108
168
|
// array may not be in the same order as the input array
|
|
109
|
-
setConnectedMcpServers((prev) =>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
169
|
+
setConnectedMcpServers((prev) => {
|
|
170
|
+
const existing = prev.find((s) => equalsMcpServer(s, mcpServerInfo));
|
|
171
|
+
try {
|
|
172
|
+
existing?.client?.close();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// best-effort cleanup
|
|
176
|
+
}
|
|
177
|
+
return [
|
|
178
|
+
// replace the server if it already exists
|
|
179
|
+
...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),
|
|
180
|
+
failedMcpServer,
|
|
181
|
+
];
|
|
182
|
+
});
|
|
114
183
|
return failedMcpServer;
|
|
115
184
|
}
|
|
116
185
|
}));
|
|
@@ -171,11 +240,52 @@ const TamboMcpProvider = ({ mcpServers, children }) => {
|
|
|
171
240
|
});
|
|
172
241
|
}
|
|
173
242
|
// normalize the server infos
|
|
174
|
-
const mcpServerInfos =
|
|
243
|
+
const mcpServerInfos = allMcpServers.map((mcpServer) => typeof mcpServer === "string"
|
|
175
244
|
? { url: mcpServer, transport: mcp_client_1.MCPTransport.SSE }
|
|
176
245
|
: mcpServer);
|
|
177
246
|
registerMcpServers(mcpServerInfos);
|
|
178
|
-
|
|
247
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
248
|
+
}, [allMcpServers, registerTool]);
|
|
249
|
+
// Update handlers when they change
|
|
250
|
+
// We depend only on the handler refs and server identities. The linter cannot
|
|
251
|
+
// infer this shape with optional chaining and derived wrapper functions.
|
|
252
|
+
(0, react_1.useEffect)(() => {
|
|
253
|
+
const mcpServerInfos = allMcpServers.map((mcpServer) => typeof mcpServer === "string"
|
|
254
|
+
? { url: mcpServer, transport: mcp_client_1.MCPTransport.SSE }
|
|
255
|
+
: mcpServer);
|
|
256
|
+
connectedMcpServers.forEach((connectedServer) => {
|
|
257
|
+
if (!connectedServer.client) {
|
|
258
|
+
// Skip failed servers
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
// Find the matching server info to get the current handlers
|
|
262
|
+
const serverInfo = mcpServerInfos.find((info) => equalsMcpServer(connectedServer, info));
|
|
263
|
+
if (!serverInfo) {
|
|
264
|
+
// Server was removed, will be handled by the main effect
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
// Determine effective elicitation handler (per-server overrides provider)
|
|
268
|
+
const defaultElicitationHandler = providerElicitationHandler;
|
|
269
|
+
const effectiveElicitationHandler = serverInfo.handlers?.elicitation ??
|
|
270
|
+
(defaultElicitationHandler
|
|
271
|
+
? async (request) => await defaultElicitationHandler(request, serverInfo)
|
|
272
|
+
: undefined);
|
|
273
|
+
// Determine effective sampling handler (per-server overrides provider)
|
|
274
|
+
const defaultSamplingHandler = providerSamplingHandler;
|
|
275
|
+
const effectiveSamplingHandler = serverInfo.handlers?.sampling ??
|
|
276
|
+
(defaultSamplingHandler
|
|
277
|
+
? async (request) => await defaultSamplingHandler(request, serverInfo)
|
|
278
|
+
: undefined);
|
|
279
|
+
// Apply handler updates unconditionally so removals propagate
|
|
280
|
+
connectedServer.client.updateElicitationHandler?.(effectiveElicitationHandler);
|
|
281
|
+
connectedServer.client.updateSamplingHandler?.(effectiveSamplingHandler);
|
|
282
|
+
});
|
|
283
|
+
}, [
|
|
284
|
+
allMcpServers,
|
|
285
|
+
connectedMcpServers,
|
|
286
|
+
providerElicitationHandler,
|
|
287
|
+
providerSamplingHandler,
|
|
288
|
+
]);
|
|
179
289
|
return (react_1.default.createElement(McpProviderContext.Provider, { value: connectedMcpServers }, children));
|
|
180
290
|
};
|
|
181
291
|
exports.TamboMcpProvider = TamboMcpProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-mcp-provider.js","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["import { deepEqual } from \"fast-equals\";\nimport React, {\n createContext,\n FC,\n useContext,\n useEffect,\n useState,\n} from \"react\";\nimport { TamboTool } from \"../model/component-metadata\";\nimport { isContentPartArray, toText } from \"../util/content-parts\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { MCPClient, MCPTransport } from \"./mcp-client\";\n\n/**\n * Extracts error message from MCP tool result content.\n * Handles both array and string content formats.\n * Always returns a string, even for invalid/null inputs.\n * @returns The extracted error message as a string\n */\nexport function extractErrorMessage(content: unknown): string {\n if (content === undefined || content === null) {\n return \"Unknown error occurred\";\n }\n\n if (Array.isArray(content)) {\n const textItems = content\n .filter(\n (item) => item && item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text);\n\n return textItems.length > 0\n ? textItems.join(\" \")\n : \"Error occurred but no details provided\";\n }\n\n if (typeof content === \"object\") {\n return JSON.stringify(content);\n }\n\n return `${content}`;\n}\n\nexport interface McpServerInfo {\n name?: string;\n url: string;\n description?: string;\n transport?: MCPTransport;\n customHeaders?: Record<string, string>;\n}\n\nexport interface ConnectedMcpServer extends McpServerInfo {\n client: MCPClient;\n}\n\nexport interface FailedMcpServer extends McpServerInfo {\n client?: never;\n connectionError: Error;\n}\n\nexport type McpServer = ConnectedMcpServer | FailedMcpServer;\n\nconst McpProviderContext = createContext<McpServer[]>([]);\n/**\n * This provider is used to register tools from MCP servers.\n * @returns the wrapped children\n */\nexport const TamboMcpProvider: FC<{\n mcpServers: (McpServerInfo | string)[];\n children: React.ReactNode;\n}> = ({ mcpServers, children }) => {\n const { registerTool } = useTamboRegistry();\n const [connectedMcpServers, setConnectedMcpServers] = useState<McpServer[]>(\n [],\n );\n\n useEffect(() => {\n if (!mcpServers) {\n return;\n }\n async function registerMcpServers(mcpServerInfos: McpServerInfo[]) {\n // Maps tool names to the MCP client that registered them\n const mcpServerMap = new Map<string, McpServer>();\n setConnectedMcpServers((prev) =>\n // remove any servers that are not in the new list\n prev.filter((s) =>\n mcpServerInfos.some((mcpServerInfo) =>\n equalsMcpServer(s, mcpServerInfo),\n ),\n ),\n );\n\n // initialize the MCP clients, converting McpServerInfo -> McpServer\n const mcpServers = await Promise.allSettled(\n mcpServerInfos.map(async (mcpServerInfo): Promise<McpServer> => {\n try {\n const client = await MCPClient.create(\n mcpServerInfo.url,\n mcpServerInfo.transport,\n mcpServerInfo.customHeaders,\n undefined, // no oauth support yet\n undefined, // starting with no session id at first.\n );\n const connectedMcpServer = {\n ...mcpServerInfo,\n client: client,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n connectedMcpServer,\n ]);\n return connectedMcpServer;\n } catch (error) {\n const failedMcpServer = {\n ...mcpServerInfo,\n connectionError: error as Error,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n failedMcpServer,\n ]);\n return failedMcpServer;\n }\n }),\n );\n\n // note do not rely on the state\n const connectedMcpServers = mcpServers\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n // Now create a map of tool name to MCP client\n const serverToolLists = connectedMcpServers.map(async (mcpServer) => {\n const tools = (await mcpServer.client?.listTools()) ?? [];\n tools.forEach((tool) => {\n mcpServerMap.set(tool.name, mcpServer);\n });\n return tools;\n });\n const toolResults = await Promise.allSettled(serverToolLists);\n\n // Just log the failed tools, we can't do anything about them\n const failedTools = toolResults.filter(\n (result) => result.status === \"rejected\",\n );\n if (failedTools.length > 0) {\n console.error(\n \"Failed to register tools from MCP servers:\",\n failedTools.map((result) => result.reason),\n );\n }\n\n // Register the successful tools\n const allTools = toolResults\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value)\n .flat();\n allTools.forEach((tool) => {\n registerTool({\n description: tool.description ?? \"\",\n name: tool.name,\n tool: async (args: Record<string, unknown>) => {\n const mcpServer = mcpServerMap.get(tool.name);\n if (!mcpServer) {\n // should never happen\n throw new Error(`MCP server for tool ${tool.name} not found`);\n }\n if (!mcpServer.client) {\n // this can't actually happen because the tool can't be registered if the server is not connected\n throw new Error(\n `MCP server for tool ${tool.name} is not connected`,\n );\n }\n const result = await mcpServer.client.callTool(tool.name, args);\n if (result.isError) {\n const errorMessage = extractErrorMessage(result.content);\n throw new Error(errorMessage);\n }\n return result.content;\n },\n toolSchema: tool.inputSchema as TamboTool[\"toolSchema\"],\n transformToContent: (content: unknown) => {\n // MCP tools can return content in various formats; pass through arrays of content parts\n // unchanged, otherwise stringify into a text content part.\n if (isContentPartArray(content)) {\n return content;\n }\n return [{ type: \"text\", text: toText(content) }];\n },\n });\n });\n }\n\n // normalize the server infos\n const mcpServerInfos = mcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n registerMcpServers(mcpServerInfos);\n }, [mcpServers, registerTool]);\n\n return (\n <McpProviderContext.Provider value={connectedMcpServers}>\n {children}\n </McpProviderContext.Provider>\n );\n};\n\n/**\n * Hook to access the actual MCP servers, as they are connected (or fail to\n * connect).\n *\n * You can call methods on the MCP client that is included in the MCP server\n * object.\n *\n * If the server fails to connect, the `client` property will be `undefined` and\n * the `connectionError` property will be set.\n *\n * For example, to forcibly disconnect and reconnect all MCP servers:\n *\n * ```tsx\n * const mcpServers = useTamboMcpServers();\n * mcpServers.forEach((mcpServer) => {\n * mcpServer.client?.reconnect();\n * });\n * ```\n *\n * Note that the MCP servers are not guaranteed to be in the same order as the\n * input array, because they are added as they are connected.\n * @returns The MCP servers\n */\nexport const useTamboMcpServers = () => {\n return useContext(McpProviderContext);\n};\nfunction equalsMcpServer(s: McpServer, mcpServerInfo: McpServerInfo): boolean {\n return (\n s.url === mcpServerInfo.url &&\n s.transport === mcpServerInfo.transport &&\n deepEqual(s.customHeaders, mcpServerInfo.customHeaders)\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tambo-mcp-provider.js","sourceRoot":"","sources":["../../src/mcp/tambo-mcp-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["import { deepEqual } from \"fast-equals\";\nimport React, {\n createContext,\n FC,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { TamboTool } from \"../model/component-metadata\";\nimport { useTamboMcpToken } from \"../providers/tambo-mcp-token-provider\";\nimport { useTamboRegistry } from \"../providers/tambo-registry-provider\";\nimport { isContentPartArray, toText } from \"../util/content-parts\";\nimport { MCPClient, MCPHandlers, MCPTransport } from \"./mcp-client\";\n\n/**\n * Extracts error message from MCP tool result content.\n * Handles both array and string content formats.\n * Always returns a string, even for invalid/null inputs.\n * @returns The extracted error message as a string\n */\nexport function extractErrorMessage(content: unknown): string {\n if (content === undefined || content === null) {\n return \"Unknown error occurred\";\n }\n\n if (Array.isArray(content)) {\n const textItems = content\n .filter(\n (item) => item && item.type === \"text\" && typeof item.text === \"string\",\n )\n .map((item) => item.text);\n\n return textItems.length > 0\n ? textItems.join(\" \")\n : \"Error occurred but no details provided\";\n }\n\n if (typeof content === \"object\") {\n return JSON.stringify(content);\n }\n\n return `${content}`;\n}\n\n/**\n * Configuration for connecting to an MCP server.\n */\nexport interface McpServerInfo {\n /** Optional name for the MCP server */\n name?: string;\n /** The URL of the MCP server to connect to */\n url: string;\n /** Optional description of the MCP server */\n description?: string;\n /** The transport type to use (SSE or HTTP). Defaults to SSE for string URLs */\n transport?: MCPTransport;\n /** Optional custom headers to include in requests */\n customHeaders?: Record<string, string>;\n /**\n * Optional handlers for elicitation and sampling requests from the server.\n * Note: These callbacks should be stable (e.g., wrapped in useCallback or defined outside the component)\n * to avoid constant re-registration of the MCP server on every render.\n */\n handlers?: Partial<MCPHandlers>;\n}\n\nexport interface ConnectedMcpServer extends McpServerInfo {\n client: MCPClient;\n}\n\nexport interface FailedMcpServer extends McpServerInfo {\n client?: never;\n connectionError: Error;\n}\n\nexport type McpServer = ConnectedMcpServer | FailedMcpServer;\n\n/**\n * Provider-level MCP handlers that receive the McpServerInfo as context in addition to the request.\n * These handlers are applied to all MCP servers unless overridden by per-server handlers.\n */\nexport interface ProviderMCPHandlers {\n elicitation?: (\n request: Parameters<MCPHandlers[\"elicitation\"]>[0],\n serverInfo: McpServerInfo,\n ) => ReturnType<MCPHandlers[\"elicitation\"]>;\n sampling?: (\n request: Parameters<MCPHandlers[\"sampling\"]>[0],\n serverInfo: McpServerInfo,\n ) => ReturnType<MCPHandlers[\"sampling\"]>;\n}\n\nconst McpProviderContext = createContext<McpServer[]>([]);\n\n// Constant for the internal Tambo MCP server name\nconst TAMBO_INTERNAL_MCP_SERVER_NAME = \"__tambo_internal_mcp_server__\";\n\n/**\n * This provider is used to register tools from MCP servers.\n * It automatically includes an internal Tambo MCP server when an MCP access token is available.\n * @param props - The provider props\n * @param props.mcpServers - Array of MCP server configurations\n * @param props.handlers - Optional handlers applied to all MCP servers unless overridden per-server\n * @param props.children - The children to wrap\n * @returns The TamboMcpProvider component\n */\nexport const TamboMcpProvider: FC<{\n mcpServers: (McpServerInfo | string)[];\n handlers?: ProviderMCPHandlers;\n children: React.ReactNode;\n}> = ({ mcpServers, handlers, children }) => {\n const { registerTool } = useTamboRegistry();\n const { mcpAccessToken, tamboBaseUrl } = useTamboMcpToken();\n const providerElicitationHandler = handlers?.elicitation;\n const providerSamplingHandler = handlers?.sampling;\n const [connectedMcpServers, setConnectedMcpServers] = useState<McpServer[]>(\n [],\n );\n\n // Combine user-provided MCP servers with the internal Tambo MCP server\n const allMcpServers = useMemo(() => {\n const servers = [...mcpServers];\n\n // Add internal Tambo MCP server if we have an access token and a base URL\n if (mcpAccessToken && tamboBaseUrl) {\n // Build the internal MCP URL robustly, preserving any existing base path\n const base = new URL(tamboBaseUrl);\n base.pathname = `${base.pathname.replace(/\\/+$/, \"\")}/mcp`;\n const tamboMcpUrl = base.toString();\n servers.push({\n name: TAMBO_INTERNAL_MCP_SERVER_NAME,\n url: tamboMcpUrl,\n transport: MCPTransport.HTTP,\n customHeaders: {\n Authorization: `Bearer ${mcpAccessToken}`,\n },\n });\n }\n\n return servers;\n }, [mcpServers, mcpAccessToken, tamboBaseUrl]);\n\n useEffect(() => {\n if (!allMcpServers.length) {\n return;\n }\n async function registerMcpServers(mcpServerInfos: McpServerInfo[]) {\n // Maps tool names to the MCP client that registered them\n const mcpServerMap = new Map<string, McpServer>();\n setConnectedMcpServers((prev) =>\n // remove any servers that are not in the new list\n prev.filter((s) =>\n mcpServerInfos.some((mcpServerInfo) =>\n equalsMcpServer(s, mcpServerInfo),\n ),\n ),\n );\n\n // initialize the MCP clients, converting McpServerInfo -> McpServer\n const mcpServers = await Promise.allSettled(\n mcpServerInfos.map(async (mcpServerInfo): Promise<McpServer> => {\n try {\n // Merge provider handlers with per-server handlers (per-server takes precedence)\n const effectiveHandlers: Partial<MCPHandlers> = {};\n\n // Apply provider elicitation handler if present and not overridden\n if (mcpServerInfo.handlers?.elicitation) {\n effectiveHandlers.elicitation =\n mcpServerInfo.handlers.elicitation;\n } else if (providerElicitationHandler) {\n const elicitationHandler = providerElicitationHandler;\n effectiveHandlers.elicitation = async (request) =>\n await elicitationHandler(request, mcpServerInfo);\n }\n\n // Apply provider sampling handler if present and not overridden\n if (mcpServerInfo.handlers?.sampling) {\n effectiveHandlers.sampling = mcpServerInfo.handlers.sampling;\n } else if (providerSamplingHandler) {\n const samplingHandler = providerSamplingHandler;\n effectiveHandlers.sampling = async (request) =>\n await samplingHandler(request, mcpServerInfo);\n }\n\n const client = await MCPClient.create(\n mcpServerInfo.url,\n mcpServerInfo.transport,\n mcpServerInfo.customHeaders,\n undefined, // no oauth support yet\n undefined, // starting with no session id at first.\n effectiveHandlers,\n );\n const connectedMcpServer = {\n ...mcpServerInfo,\n client: client,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => {\n const existing = prev.find((s) =>\n equalsMcpServer(s, mcpServerInfo),\n );\n try {\n existing?.client?.close();\n } catch {\n // best-effort cleanup\n }\n return [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n connectedMcpServer,\n ];\n });\n return connectedMcpServer;\n } catch (error) {\n const failedMcpServer = {\n ...mcpServerInfo,\n connectionError: error as Error,\n };\n // note because the promises may resolve in any order, the resulting\n // array may not be in the same order as the input array\n setConnectedMcpServers((prev) => {\n const existing = prev.find((s) =>\n equalsMcpServer(s, mcpServerInfo),\n );\n try {\n existing?.client?.close();\n } catch {\n // best-effort cleanup\n }\n return [\n // replace the server if it already exists\n ...prev.filter((s) => !equalsMcpServer(s, mcpServerInfo)),\n failedMcpServer,\n ];\n });\n return failedMcpServer;\n }\n }),\n );\n\n // note do not rely on the state\n const connectedMcpServers = mcpServers\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n // Now create a map of tool name to MCP client\n const serverToolLists = connectedMcpServers.map(async (mcpServer) => {\n const tools = (await mcpServer.client?.listTools()) ?? [];\n tools.forEach((tool) => {\n mcpServerMap.set(tool.name, mcpServer);\n });\n return tools;\n });\n const toolResults = await Promise.allSettled(serverToolLists);\n\n // Just log the failed tools, we can't do anything about them\n const failedTools = toolResults.filter(\n (result) => result.status === \"rejected\",\n );\n if (failedTools.length > 0) {\n console.error(\n \"Failed to register tools from MCP servers:\",\n failedTools.map((result) => result.reason),\n );\n }\n\n // Register the successful tools\n const allTools = toolResults\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value)\n .flat();\n allTools.forEach((tool) => {\n registerTool({\n description: tool.description ?? \"\",\n name: tool.name,\n tool: async (args: Record<string, unknown>) => {\n const mcpServer = mcpServerMap.get(tool.name);\n if (!mcpServer) {\n // should never happen\n throw new Error(`MCP server for tool ${tool.name} not found`);\n }\n if (!mcpServer.client) {\n // this can't actually happen because the tool can't be registered if the server is not connected\n throw new Error(\n `MCP server for tool ${tool.name} is not connected`,\n );\n }\n const result = await mcpServer.client.callTool(tool.name, args);\n if (result.isError) {\n const errorMessage = extractErrorMessage(result.content);\n throw new Error(errorMessage);\n }\n return result.content;\n },\n toolSchema: tool.inputSchema as TamboTool[\"toolSchema\"],\n transformToContent: (content: unknown) => {\n // MCP tools can return content in various formats; pass through arrays of content parts\n // unchanged, otherwise stringify into a text content part.\n if (isContentPartArray(content)) {\n return content;\n }\n return [{ type: \"text\", text: toText(content) }];\n },\n });\n });\n }\n\n // normalize the server infos\n const mcpServerInfos = allMcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n registerMcpServers(mcpServerInfos);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [allMcpServers, registerTool]);\n\n // Update handlers when they change\n // We depend only on the handler refs and server identities. The linter cannot\n // infer this shape with optional chaining and derived wrapper functions.\n useEffect(() => {\n const mcpServerInfos = allMcpServers.map((mcpServer) =>\n typeof mcpServer === \"string\"\n ? { url: mcpServer, transport: MCPTransport.SSE }\n : mcpServer,\n );\n\n connectedMcpServers.forEach((connectedServer) => {\n if (!connectedServer.client) {\n // Skip failed servers\n return;\n }\n\n // Find the matching server info to get the current handlers\n const serverInfo = mcpServerInfos.find((info) =>\n equalsMcpServer(connectedServer, info),\n );\n\n if (!serverInfo) {\n // Server was removed, will be handled by the main effect\n return;\n }\n\n // Determine effective elicitation handler (per-server overrides provider)\n const defaultElicitationHandler = providerElicitationHandler;\n const effectiveElicitationHandler =\n serverInfo.handlers?.elicitation ??\n (defaultElicitationHandler\n ? async (request) =>\n await defaultElicitationHandler(request, serverInfo)\n : undefined);\n\n // Determine effective sampling handler (per-server overrides provider)\n const defaultSamplingHandler = providerSamplingHandler;\n const effectiveSamplingHandler =\n serverInfo.handlers?.sampling ??\n (defaultSamplingHandler\n ? async (request) => await defaultSamplingHandler(request, serverInfo)\n : undefined);\n\n // Apply handler updates unconditionally so removals propagate\n connectedServer.client.updateElicitationHandler?.(\n effectiveElicitationHandler,\n );\n connectedServer.client.updateSamplingHandler?.(effectiveSamplingHandler);\n });\n }, [\n allMcpServers,\n connectedMcpServers,\n providerElicitationHandler,\n providerSamplingHandler,\n ]);\n\n return (\n <McpProviderContext.Provider value={connectedMcpServers}>\n {children}\n </McpProviderContext.Provider>\n );\n};\n\n/**\n * Hook to access the actual MCP servers, as they are connected (or fail to\n * connect).\n *\n * You can call methods on the MCP client that is included in the MCP server\n * object.\n *\n * If the server fails to connect, the `client` property will be `undefined` and\n * the `connectionError` property will be set.\n *\n * For example, to forcibly disconnect and reconnect all MCP servers:\n *\n * ```tsx\n * const mcpServers = useTamboMcpServers();\n * mcpServers.forEach((mcpServer) => {\n * mcpServer.client?.reconnect();\n * });\n * ```\n *\n * Note that the MCP servers are not guaranteed to be in the same order as the\n * input array, because they are added as they are connected.\n * @returns The MCP servers\n */\nexport const useTamboMcpServers = () => {\n return useContext(McpProviderContext);\n};\nfunction equalsMcpServer(s: McpServer, mcpServerInfo: McpServerInfo): boolean {\n return (\n s.url === mcpServerInfo.url &&\n s.transport === mcpServerInfo.transport &&\n deepEqual(s.customHeaders, mcpServerInfo.customHeaders)\n );\n}\n"]}
|
|
@@ -44,7 +44,7 @@ export interface TamboTool<Args extends z.ZodTuple<any, any> = z.ZodTuple<any, a
|
|
|
44
44
|
* @param result - The result returned by the tool function
|
|
45
45
|
* @returns An array of content parts to be sent back to the AI
|
|
46
46
|
*/
|
|
47
|
-
transformToContent?: (result: z.infer<Returns>) => TamboAI.Beta.Threads.ChatCompletionContentPart[];
|
|
47
|
+
transformToContent?: (result: z.infer<Returns>) => Promise<TamboAI.Beta.Threads.ChatCompletionContentPart[]> | TamboAI.Beta.Threads.ChatCompletionContentPart[];
|
|
48
48
|
}
|
|
49
49
|
export type TamboToolAssociations = Record<string, string[]>;
|
|
50
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-metadata.d.ts","sourceRoot":"","sources":["../../src/model/component-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,KAAK,eAAe,MAAM,oBAAoB,CAAC;AACtD,+FAA+F;AAC/F,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,GAAG;IACnD,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;CAC7C,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,4BACf,SAAQ,OAAO,CAAC,4BAA4B;IAC5C,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,mBAAmB,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,UAAU,EAAE,4BAA4B,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAoB,SAAQ,OAAO,CAAC,kBAAkB;IACrE,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,gBAAgB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEpE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,GAAG;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,SAAS,CACxB,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,EACxD,OAAO,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU;IAE3C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnD,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC;IAC1D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CACnB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"component-metadata.d.ts","sourceRoot":"","sources":["../../src/model/component-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,KAAK,eAAe,MAAM,oBAAoB,CAAC;AACtD,+FAA+F;AAC/F,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,GAAG;IACnD,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;CAC7C,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,4BACf,SAAQ,OAAO,CAAC,4BAA4B;IAC5C,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,mBAAmB,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,UAAU,EAAE,4BAA4B,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAoB,SAAQ,OAAO,CAAC,kBAAkB;IACrE,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,gBAAgB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEpE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,GAAG;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,SAAS,CACxB,IAAI,SAAS,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,EACxD,OAAO,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU;IAE3C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnD,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC;IAC1D;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,CACnB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAEtB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,GACzD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC;CACtD;AAED,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAC7D;;GAEG;AAEH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC,UAAU,GAAG,WAAW,CAAC;IACzC;;;;OAIG;IACH,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IACtC,uDAAuD;IACvD,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;CAC/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-metadata.js","sourceRoot":"","sources":["../../src/model/component-metadata.ts"],"names":[],"mappings":"","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { JSONSchema7 } from \"json-schema\";\nimport { ComponentType } from \"react\";\nimport z from \"zod\";\nimport type zodToJsonSchema from \"zod-to-json-schema\";\n/** Extension of the ToolParameters interface from Tambo AI to include JSONSchema definition */\nexport type ParameterSpec = TamboAI.ToolParameters & {\n schema?: ReturnType<typeof zodToJsonSchema>;\n};\n\n/**\n * Extends the base ContextTool interface from Tambo AI to include schema information\n * for parameter validation using zod-to-json-schema.\n */\nexport interface ComponentContextToolMetadata\n extends TamboAI.ComponentContextToolMetadata {\n parameters: ParameterSpec[];\n}\n\nexport interface ComponentContextTool {\n getComponentContext: (...args: any[]) => Promise<any>;\n definition: ComponentContextToolMetadata;\n}\n\nexport interface RegisteredComponent extends TamboAI.AvailableComponent {\n component: ComponentType<any>;\n loadingComponent?: ComponentType<any>;\n}\n\nexport type ComponentRegistry = Record<string, RegisteredComponent>;\n\nexport type TamboToolRegistry = Record<string, TamboTool>;\n\n/**\n * A JSON Schema that is compatible with the MCP.\n * This is a simplified JSON Schema that is compatible with the MCPClient and the toolSchema.\n *\n * Do not export this type from the SDK.\n */\nexport type JSONSchemaLite = ReturnType<typeof zodToJsonSchema> & {\n description?: string;\n};\n\nexport interface TamboTool<\n Args extends z.ZodTuple<any, any> = z.ZodTuple<any, any>,\n Returns extends z.ZodTypeAny = z.ZodTypeAny,\n> {\n name: string;\n description: string;\n tool: (...args: z.infer<Args>) => z.infer<Returns>;\n toolSchema: z.ZodFunction<Args, Returns> | JSONSchemaLite;\n /**\n * Optional function to transform the tool's return value into an array of content parts.\n * If not provided, the return value will be converted to a string and wrapped in a text content part.\n * @param result - The result returned by the tool function\n * @returns An array of content parts to be sent back to the AI\n */\n transformToContent?: (\n result: z.infer<Returns>,\n )
|
|
1
|
+
{"version":3,"file":"component-metadata.js","sourceRoot":"","sources":["../../src/model/component-metadata.ts"],"names":[],"mappings":"","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { JSONSchema7 } from \"json-schema\";\nimport { ComponentType } from \"react\";\nimport z from \"zod\";\nimport type zodToJsonSchema from \"zod-to-json-schema\";\n/** Extension of the ToolParameters interface from Tambo AI to include JSONSchema definition */\nexport type ParameterSpec = TamboAI.ToolParameters & {\n schema?: ReturnType<typeof zodToJsonSchema>;\n};\n\n/**\n * Extends the base ContextTool interface from Tambo AI to include schema information\n * for parameter validation using zod-to-json-schema.\n */\nexport interface ComponentContextToolMetadata\n extends TamboAI.ComponentContextToolMetadata {\n parameters: ParameterSpec[];\n}\n\nexport interface ComponentContextTool {\n getComponentContext: (...args: any[]) => Promise<any>;\n definition: ComponentContextToolMetadata;\n}\n\nexport interface RegisteredComponent extends TamboAI.AvailableComponent {\n component: ComponentType<any>;\n loadingComponent?: ComponentType<any>;\n}\n\nexport type ComponentRegistry = Record<string, RegisteredComponent>;\n\nexport type TamboToolRegistry = Record<string, TamboTool>;\n\n/**\n * A JSON Schema that is compatible with the MCP.\n * This is a simplified JSON Schema that is compatible with the MCPClient and the toolSchema.\n *\n * Do not export this type from the SDK.\n */\nexport type JSONSchemaLite = ReturnType<typeof zodToJsonSchema> & {\n description?: string;\n};\n\nexport interface TamboTool<\n Args extends z.ZodTuple<any, any> = z.ZodTuple<any, any>,\n Returns extends z.ZodTypeAny = z.ZodTypeAny,\n> {\n name: string;\n description: string;\n tool: (...args: z.infer<Args>) => z.infer<Returns>;\n toolSchema: z.ZodFunction<Args, Returns> | JSONSchemaLite;\n /**\n * Optional function to transform the tool's return value into an array of content parts.\n * If not provided, the return value will be converted to a string and wrapped in a text content part.\n * @param result - The result returned by the tool function\n * @returns An array of content parts to be sent back to the AI\n */\n transformToContent?: (\n result: z.infer<Returns>,\n ) =>\n | Promise<TamboAI.Beta.Threads.ChatCompletionContentPart[]>\n | TamboAI.Beta.Threads.ChatCompletionContentPart[];\n}\n\nexport type TamboToolAssociations = Record<string, string[]>;\n/**\n * A component that can be registered with the TamboRegistryProvider.\n */\n\nexport interface TamboComponent {\n /** The name of the component */\n name: string;\n /** The description of the component */\n description: string;\n /**\n * The React component to render.\n *\n * Make sure to pass the Component itself, not an instance of the component. For example,\n * if you have a component like this:\n *\n * ```tsx\n * const MyComponent = () => {\n * return <div>My Component</div>;\n * };\n * ```\n *\n * You should pass the `Component`:\n *\n * ```tsx\n * const components = [MyComponent];\n * <TamboRegistryProvider components={components} />\n * ```\n */\n component: ComponentType<any>;\n\n /**\n * A zod schema for the component props. (Recommended)\n * Either this or propsDefinition must be provided, but not both.\n */\n propsSchema?: z.ZodTypeAny | JSONSchema7;\n /**\n * The props definition of the component as a JSON object.\n * Either this or propsSchema must be provided, but not both.\n * @deprecated Use propsSchema instead.\n */\n propsDefinition?: any;\n /** The loading component to render while the component is loading */\n loadingComponent?: ComponentType<any>;\n /** The tools that are associated with the component */\n associatedTools?: TamboTool[];\n}\n"]}
|
|
@@ -9,6 +9,7 @@ const react_2 = __importDefault(require("react"));
|
|
|
9
9
|
const generate_component_response_1 = require("../../model/generate-component-response");
|
|
10
10
|
const tambo_client_provider_1 = require("../tambo-client-provider");
|
|
11
11
|
const tambo_context_helpers_provider_1 = require("../tambo-context-helpers-provider");
|
|
12
|
+
const tambo_mcp_token_provider_1 = require("../tambo-mcp-token-provider");
|
|
12
13
|
const tambo_registry_provider_1 = require("../tambo-registry-provider");
|
|
13
14
|
const tambo_thread_provider_1 = require("../tambo-thread-provider");
|
|
14
15
|
// Mock crypto.randomUUID
|
|
@@ -39,7 +40,8 @@ const createMockMessage = (overrides = {}) => ({
|
|
|
39
40
|
const createWrapper = (initialMessages = []) => {
|
|
40
41
|
const TestWrapper = ({ children }) => (react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, { components: [], tools: [] },
|
|
41
42
|
react_2.default.createElement(tambo_context_helpers_provider_1.TamboContextHelpersProvider, null,
|
|
42
|
-
react_2.default.createElement(
|
|
43
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
44
|
+
react_2.default.createElement(tambo_thread_provider_1.TamboThreadProvider, { initialMessages: initialMessages }, children)))));
|
|
43
45
|
TestWrapper.displayName = "TestWrapper";
|
|
44
46
|
return TestWrapper;
|
|
45
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-thread-provider-initial-messages.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-thread-provider-initial-messages.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport {\n GenerationStage,\n TamboThreadMessage,\n} from \"../../model/generate-component-response\";\nimport { useTamboClient, useTamboQueryClient } from \"../tambo-client-provider\";\nimport { TamboContextHelpersProvider } from \"../tambo-context-helpers-provider\";\nimport { TamboRegistryProvider } from \"../tambo-registry-provider\";\nimport { TamboThreadProvider, useTamboThread } from \"../tambo-thread-provider\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\n// Mock crypto.randomUUID\nObject.defineProperty(global, \"crypto\", {\n value: {\n randomUUID: jest.fn().mockReturnValue(\"test-uuid\"),\n },\n});\n\n// Mock the required providers\njest.mock(\"../tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn(),\n}));\njest.mock(\"@tambo-ai/typescript-sdk\", () => ({\n advanceStream: jest.fn(),\n}));\n\n// Test utilities\nconst createMockMessage = (\n overrides: Partial<TamboThreadMessage> = {},\n): TamboThreadMessage => ({\n id: \"test-message-1\",\n content: [{ type: \"text\", text: \"Hello\" }],\n role: \"user\",\n threadId: \"test-thread-1\",\n createdAt: new Date().toISOString(),\n componentState: {},\n ...overrides,\n});\n\n// Test wrapper\nconst createWrapper = (initialMessages: TamboThreadMessage[] = []) => {\n const TestWrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboRegistryProvider components={[]} tools={[]}>\n <TamboContextHelpersProvider>\n <TamboThreadProvider initialMessages={initialMessages}>\n {children}\n </TamboThreadProvider>\n </TamboContextHelpersProvider>\n </TamboRegistryProvider>\n );\n TestWrapper.displayName = \"TestWrapper\";\n return TestWrapper;\n};\n\ndescribe(\"TamboThreadProvider with initial messages\", () => {\n const mockClient: PartialTamboAI = {\n beta: {\n threads: {\n advance: jest.fn(),\n advanceByID: jest.fn(),\n cancel: jest.fn(),\n messages: {\n create: jest.fn(),\n },\n },\n },\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n (useTamboClient as jest.Mock).mockReturnValue(mockClient);\n // Provide a minimal mock for the query client used by the provider\n const mockQueryClient = {\n setQueryData: jest.fn(),\n invalidateQueries: jest.fn(),\n };\n (useTamboQueryClient as jest.Mock).mockReturnValue(mockQueryClient);\n (advanceStream as jest.Mock).mockImplementation(async function* () {\n yield {\n responseMessageDto: {\n id: \"response-1\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Hello back!\" }],\n threadId: \"new-thread-id\",\n componentState: {},\n createdAt: new Date().toISOString(),\n },\n generationStage: GenerationStage.COMPLETE,\n };\n });\n });\n\n it(\"should initialize with empty messages when no initial messages provided\", () => {\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.thread.messages).toEqual([]);\n });\n\n it(\"should initialize with provided initial messages\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n createMockMessage({\n id: \"initial-2\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Hello!\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n expect(result.current.thread.messages).toHaveLength(2);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n expect(result.current.thread.messages[1].content[0].text).toBe(\"Hello!\");\n });\n\n it(\"should include initial messages when sending a message to a new thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called with initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.objectContaining({\n initialMessages: [\n {\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n role: \"system\",\n additionalContext: undefined,\n },\n ],\n }),\n undefined,\n );\n });\n\n it(\"should not include initial messages when sending to an existing thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread first\n await act(async () => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called without initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.not.objectContaining({\n initialMessages: expect.anything(),\n }),\n \"existing-thread-id\",\n );\n });\n\n it(\"should reset to initial messages when starting a new thread\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread\n act(() => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n // Start a new thread\n act(() => {\n result.current.startNewThread();\n });\n\n expect(result.current.thread.messages).toHaveLength(1);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"tambo-thread-provider-initial-messages.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-thread-provider-initial-messages.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport React from \"react\";\nimport { DeepPartial } from \"ts-essentials\";\nimport {\n GenerationStage,\n TamboThreadMessage,\n} from \"../../model/generate-component-response\";\nimport { useTamboClient, useTamboQueryClient } from \"../tambo-client-provider\";\nimport { TamboContextHelpersProvider } from \"../tambo-context-helpers-provider\";\nimport { TamboMcpTokenProvider } from \"../tambo-mcp-token-provider\";\nimport { TamboRegistryProvider } from \"../tambo-registry-provider\";\nimport { TamboThreadProvider, useTamboThread } from \"../tambo-thread-provider\";\n\ntype PartialTamboAI = DeepPartial<TamboAI>;\n\n// Mock crypto.randomUUID\nObject.defineProperty(global, \"crypto\", {\n value: {\n randomUUID: jest.fn().mockReturnValue(\"test-uuid\"),\n },\n});\n\n// Mock the required providers\njest.mock(\"../tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn(),\n}));\njest.mock(\"@tambo-ai/typescript-sdk\", () => ({\n advanceStream: jest.fn(),\n}));\n\n// Test utilities\nconst createMockMessage = (\n overrides: Partial<TamboThreadMessage> = {},\n): TamboThreadMessage => ({\n id: \"test-message-1\",\n content: [{ type: \"text\", text: \"Hello\" }],\n role: \"user\",\n threadId: \"test-thread-1\",\n createdAt: new Date().toISOString(),\n componentState: {},\n ...overrides,\n});\n\n// Test wrapper\nconst createWrapper = (initialMessages: TamboThreadMessage[] = []) => {\n const TestWrapper = ({ children }: { children: React.ReactNode }) => (\n <TamboRegistryProvider components={[]} tools={[]}>\n <TamboContextHelpersProvider>\n <TamboMcpTokenProvider>\n <TamboThreadProvider initialMessages={initialMessages}>\n {children}\n </TamboThreadProvider>\n </TamboMcpTokenProvider>\n </TamboContextHelpersProvider>\n </TamboRegistryProvider>\n );\n TestWrapper.displayName = \"TestWrapper\";\n return TestWrapper;\n};\n\ndescribe(\"TamboThreadProvider with initial messages\", () => {\n const mockClient: PartialTamboAI = {\n beta: {\n threads: {\n advance: jest.fn(),\n advanceByID: jest.fn(),\n cancel: jest.fn(),\n messages: {\n create: jest.fn(),\n },\n },\n },\n };\n\n beforeEach(() => {\n jest.clearAllMocks();\n (useTamboClient as jest.Mock).mockReturnValue(mockClient);\n // Provide a minimal mock for the query client used by the provider\n const mockQueryClient = {\n setQueryData: jest.fn(),\n invalidateQueries: jest.fn(),\n };\n (useTamboQueryClient as jest.Mock).mockReturnValue(mockQueryClient);\n (advanceStream as jest.Mock).mockImplementation(async function* () {\n yield {\n responseMessageDto: {\n id: \"response-1\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Hello back!\" }],\n threadId: \"new-thread-id\",\n componentState: {},\n createdAt: new Date().toISOString(),\n },\n generationStage: GenerationStage.COMPLETE,\n };\n });\n });\n\n it(\"should initialize with empty messages when no initial messages provided\", () => {\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(),\n });\n\n expect(result.current.thread.messages).toEqual([]);\n });\n\n it(\"should initialize with provided initial messages\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n createMockMessage({\n id: \"initial-2\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Hello!\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n expect(result.current.thread.messages).toHaveLength(2);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n expect(result.current.thread.messages[1].content[0].text).toBe(\"Hello!\");\n });\n\n it(\"should include initial messages when sending a message to a new thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called with initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.objectContaining({\n initialMessages: [\n {\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n role: \"system\",\n additionalContext: undefined,\n },\n ],\n }),\n undefined,\n );\n });\n\n it(\"should not include initial messages when sending to an existing thread\", async () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread first\n await act(async () => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n await act(async () => {\n await result.current.sendThreadMessage(\"Test message\");\n });\n\n // Check that advanceStream was called without initial messages\n expect(advanceStream).toHaveBeenCalledWith(\n mockClient,\n expect.not.objectContaining({\n initialMessages: expect.anything(),\n }),\n \"existing-thread-id\",\n );\n });\n\n it(\"should reset to initial messages when starting a new thread\", () => {\n const initialMessages: TamboThreadMessage[] = [\n createMockMessage({\n id: \"initial-1\",\n role: \"system\",\n content: [{ type: \"text\", text: \"You are a helpful assistant.\" }],\n }),\n ];\n\n const { result } = renderHook(() => useTamboThread(), {\n wrapper: createWrapper(initialMessages),\n });\n\n // Switch to an existing thread\n act(() => {\n result.current.switchCurrentThread(\"existing-thread-id\", false);\n });\n\n // Start a new thread\n act(() => {\n result.current.startNewThread();\n });\n\n expect(result.current.thread.messages).toHaveLength(1);\n expect(result.current.thread.messages[0].content[0].text).toBe(\n \"You are a helpful assistant.\",\n );\n });\n});\n"]}
|