@tambo-ai/react 0.20.2 → 0.20.4
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/__tests__/use-suggestions.test.js +66 -23
- package/dist/hooks/__tests__/use-suggestions.test.js.map +1 -1
- package/dist/hooks/__tests__/use-tambo-threads.test.d.ts +2 -0
- package/dist/hooks/__tests__/use-tambo-threads.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/use-tambo-threads.test.js +212 -0
- package/dist/hooks/__tests__/use-tambo-threads.test.js.map +1 -0
- package/dist/hooks/react-query-hooks.d.ts +0 -8
- package/dist/hooks/react-query-hooks.d.ts.map +1 -1
- package/dist/hooks/react-query-hooks.js +0 -11
- package/dist/hooks/react-query-hooks.js.map +1 -1
- package/dist/hooks/use-suggestions.js +2 -2
- package/dist/hooks/use-suggestions.js.map +1 -1
- package/dist/hooks/use-tambo-threads.d.ts +13 -11
- package/dist/hooks/use-tambo-threads.d.ts.map +1 -1
- package/dist/hooks/use-tambo-threads.js +3 -1
- package/dist/hooks/use-tambo-threads.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-thread-provider.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-thread-provider.test.js +279 -0
- package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -0
- package/dist/providers/tambo-provider.d.ts +1 -2
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-registry-provider.js +1 -4
- package/dist/providers/tambo-registry-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js +29 -25
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/setupTests.d.ts +3 -0
- package/dist/setupTests.d.ts.map +1 -0
- package/dist/setupTests.js +8 -0
- package/dist/setupTests.js.map +1 -0
- package/dist/testing/tools.d.ts +24 -0
- package/dist/testing/tools.d.ts.map +1 -0
- package/dist/testing/tools.js +31 -0
- package/dist/testing/tools.js.map +1 -0
- package/dist/testing/types.d.ts +4 -0
- package/dist/testing/types.d.ts.map +1 -0
- package/dist/testing/types.js +3 -0
- package/dist/testing/types.js.map +1 -0
- package/esm/hooks/__tests__/use-suggestions.test.js +69 -26
- package/esm/hooks/__tests__/use-suggestions.test.js.map +1 -1
- package/esm/hooks/__tests__/use-tambo-threads.test.d.ts +2 -0
- package/esm/hooks/__tests__/use-tambo-threads.test.d.ts.map +1 -0
- package/esm/hooks/__tests__/use-tambo-threads.test.js +210 -0
- package/esm/hooks/__tests__/use-tambo-threads.test.js.map +1 -0
- package/esm/hooks/react-query-hooks.d.ts +0 -8
- package/esm/hooks/react-query-hooks.d.ts.map +1 -1
- package/esm/hooks/react-query-hooks.js +0 -10
- package/esm/hooks/react-query-hooks.js.map +1 -1
- package/esm/hooks/use-suggestions.js +3 -3
- package/esm/hooks/use-suggestions.js.map +1 -1
- package/esm/hooks/use-tambo-threads.d.ts +13 -11
- package/esm/hooks/use-tambo-threads.d.ts.map +1 -1
- package/esm/hooks/use-tambo-threads.js +3 -1
- package/esm/hooks/use-tambo-threads.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-thread-provider.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-thread-provider.test.js +274 -0
- package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -0
- package/esm/providers/tambo-provider.d.ts +1 -2
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-registry-provider.js +1 -4
- package/esm/providers/tambo-registry-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js +29 -25
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/setupTests.d.ts +3 -0
- package/esm/setupTests.d.ts.map +1 -0
- package/esm/setupTests.js +6 -0
- package/esm/setupTests.js.map +1 -0
- package/esm/testing/tools.d.ts +24 -0
- package/esm/testing/tools.d.ts.map +1 -0
- package/esm/testing/tools.js +25 -0
- package/esm/testing/tools.js.map +1 -0
- package/esm/testing/types.d.ts +4 -0
- package/esm/testing/types.d.ts.map +1 -0
- package/esm/testing/types.js +2 -0
- package/esm/testing/types.js.map +1 -0
- package/package.json +8 -6
|
@@ -146,10 +146,13 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
146
146
|
return message;
|
|
147
147
|
}),
|
|
148
148
|
};
|
|
149
|
-
setThreadMap((prevMap) =>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
setThreadMap((prevMap) => {
|
|
150
|
+
const updatedThreadMap = {
|
|
151
|
+
...prevMap,
|
|
152
|
+
[threadId]: threadWithRenderedComponents,
|
|
153
|
+
};
|
|
154
|
+
return updatedThreadMap;
|
|
155
|
+
});
|
|
153
156
|
}, [client.beta.threads, componentList, currentMessageCache]);
|
|
154
157
|
(0, react_1.useEffect)(() => {
|
|
155
158
|
if (currentThreadId &&
|
|
@@ -176,13 +179,14 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
176
179
|
}
|
|
177
180
|
const prevMessages = prevMap[threadId]?.messages || [];
|
|
178
181
|
const updatedMessages = [...prevMessages, chatMessage];
|
|
179
|
-
|
|
182
|
+
const updatedThreadMap = {
|
|
180
183
|
...prevMap,
|
|
181
184
|
[threadId]: {
|
|
182
185
|
...prevMap[threadId],
|
|
183
186
|
messages: updatedMessages,
|
|
184
187
|
},
|
|
185
188
|
};
|
|
189
|
+
return updatedThreadMap;
|
|
186
190
|
});
|
|
187
191
|
if (sendToServer) {
|
|
188
192
|
// TODO: if this fails, we need to revert the local state update
|
|
@@ -253,24 +257,27 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
253
257
|
return;
|
|
254
258
|
}
|
|
255
259
|
setCurrentThreadId(threadId);
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
260
|
+
setThreadMap((prevMap) => {
|
|
261
|
+
if (prevMap[threadId]) {
|
|
262
|
+
return prevMap;
|
|
263
|
+
}
|
|
264
|
+
// If this is a new thread, add placeholder thread messages to the thread
|
|
265
|
+
const updatedThreadMap = {
|
|
266
|
+
...prevMap,
|
|
267
|
+
[threadId]: {
|
|
268
|
+
...prevMap[exports.PLACEHOLDER_THREAD.id],
|
|
269
|
+
id: threadId,
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
return updatedThreadMap;
|
|
273
|
+
});
|
|
267
274
|
if (fetch) {
|
|
268
275
|
await fetchThread(threadId);
|
|
269
276
|
}
|
|
270
277
|
}, [fetchThread, threadMap]);
|
|
271
278
|
const updateThreadStatus = (0, react_1.useCallback)((threadId, stage, statusMessage) => {
|
|
272
279
|
setThreadMap((prevMap) => {
|
|
273
|
-
|
|
280
|
+
const updatedThreadMap = {
|
|
274
281
|
...prevMap,
|
|
275
282
|
[threadId]: {
|
|
276
283
|
...prevMap[threadId],
|
|
@@ -278,6 +285,7 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
278
285
|
statusMessage: statusMessage,
|
|
279
286
|
},
|
|
280
287
|
};
|
|
288
|
+
return updatedThreadMap;
|
|
281
289
|
});
|
|
282
290
|
}, []);
|
|
283
291
|
const handleAdvanceStream = (0, react_1.useCallback)(async (stream, params, threadId, messageIdToRemove) => {
|
|
@@ -291,7 +299,7 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
291
299
|
}
|
|
292
300
|
isFirstChunk = false;
|
|
293
301
|
if (chunk.responseMessageDto.toolCallRequest) {
|
|
294
|
-
updateThreadStatus(threadId, generate_component_response_1.GenerationStage.FETCHING_CONTEXT);
|
|
302
|
+
updateThreadStatus(chunk.responseMessageDto.threadId, generate_component_response_1.GenerationStage.FETCHING_CONTEXT);
|
|
295
303
|
const toolCallResponse = await (0, tool_caller_1.handleToolCall)(chunk.responseMessageDto, toolRegistry);
|
|
296
304
|
const toolCallResponseString = typeof toolCallResponse === "string"
|
|
297
305
|
? toolCallResponse
|
|
@@ -306,10 +314,9 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
306
314
|
tool_call_id: chunk.responseMessageDto.tool_call_id,
|
|
307
315
|
},
|
|
308
316
|
};
|
|
309
|
-
updateThreadStatus(threadId, generate_component_response_1.GenerationStage.STREAMING_RESPONSE);
|
|
317
|
+
updateThreadStatus(chunk.responseMessageDto.threadId, generate_component_response_1.GenerationStage.STREAMING_RESPONSE);
|
|
310
318
|
const toolCallResponseStream = await (0, typescript_sdk_1.advanceStream)(client, toolCallResponseParams, chunk.responseMessageDto.threadId);
|
|
311
|
-
|
|
312
|
-
return await handleAdvanceStream(toolCallResponseStream, toolCallResponseParams, threadId, finalMessage?.id);
|
|
319
|
+
return await handleAdvanceStream(toolCallResponseStream, toolCallResponseParams, chunk.responseMessageDto.threadId);
|
|
313
320
|
}
|
|
314
321
|
else {
|
|
315
322
|
if (!hasSetThreadId &&
|
|
@@ -333,10 +340,7 @@ const TamboThreadProvider = ({ children, }) => {
|
|
|
333
340
|
}
|
|
334
341
|
}
|
|
335
342
|
}
|
|
336
|
-
updateThreadStatus(threadId, generate_component_response_1.GenerationStage.COMPLETE);
|
|
337
|
-
if (finalMessage) {
|
|
338
|
-
await fetchThread(finalMessage.threadId);
|
|
339
|
-
}
|
|
343
|
+
updateThreadStatus(finalMessage?.threadId ?? threadId, generate_component_response_1.GenerationStage.COMPLETE);
|
|
340
344
|
return (finalMessage ?? {
|
|
341
345
|
threadId: "",
|
|
342
346
|
content: [{ type: "text", text: `Error processing stream` }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tambo-thread-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-thread-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n GenerationStage,\n isIdleStage,\n TamboThreadMessage,\n} from \"../model/generate-component-response\";\nimport { TamboThread } from \"../model/tambo-thread\";\nimport { renderComponentIntoMessage } from \"../util/generate-component\";\nimport { getAvailableComponents, getClientContext } from \"../util/registry\";\nimport { handleToolCall } from \"../util/tool-caller\";\nimport { useTamboClient } from \"./tambo-client-provider\";\nimport { useTamboRegistry } from \"./tambo-registry-provider\";\n\nexport interface TamboThreadContextProps {\n /** The current thread */\n thread: TamboThread;\n /** Switch to a different thread */\n switchCurrentThread: (threadId: string, fetch?: boolean) => void;\n /** Start a new thread */\n startNewThread: () => void;\n /** Add a message to the current thread */\n addThreadMessage: (\n message: TamboThreadMessage,\n sendToServer: boolean,\n ) => Promise<TamboAI.Beta.Threads.ThreadMessage[]>;\n /** Update a message in the current thread */\n updateThreadMessage: (\n id: string,\n message: TamboThreadMessage,\n sendToServer: boolean,\n ) => Promise<void>;\n /** The input value of the current thread */\n inputValue: string;\n /** Set the input value of the current thread */\n setInputValue: (value: string) => void;\n /** Send a message to the current thread */\n sendThreadMessage: (\n message: string,\n options: {\n threadId?: string;\n streamResponse?: boolean;\n contextKey?: string;\n },\n ) => Promise<TamboThreadMessage>;\n /** The generation stage of the current thread - updated as the thread progresses */\n generationStage: GenerationStage;\n /** The generation status message of the current thread - updated as the thread progresses */\n generationStatusMessage: string;\n /** Whether the thread is idle */\n isIdle: boolean;\n}\n\n/**\n * This is a stub entry for when the thread is not yet created, the first time\n * the user sends a message\n *\n * Note that the consumer needs to be careful never to send `PLACEHOLDER_THREAD.id` to the server,\n * as this doesn't really exist on the server side.\n */\nexport const PLACEHOLDER_THREAD: TamboThread = {\n id: \"placeholder\",\n messages: [],\n createdAt: \"\",\n projectId: \"\",\n updatedAt: \"\",\n metadata: {},\n};\n\nexport const TamboThreadContext = createContext<TamboThreadContextProps>({\n thread: PLACEHOLDER_THREAD,\n /**\n *\n */\n switchCurrentThread: () => {\n throw new Error(\"switchCurrentThread not implemented\");\n },\n /**\n *\n */\n startNewThread: () => {\n throw new Error(\"startNewThread not implemented\");\n },\n /**\n *\n */\n addThreadMessage: () => {\n throw new Error(\"updateThreadMessageHistory not implemented\");\n },\n inputValue: \"\",\n /**\n *\n */\n setInputValue: () => {\n throw new Error(\"setInputValue not implemented\");\n },\n /**\n *\n */\n updateThreadMessage: () => {\n throw new Error(\"updateThreadMessage not implemented\");\n },\n /**\n *\n */\n sendThreadMessage: () => {\n throw new Error(\"advance not implemented\");\n },\n generationStage: GenerationStage.IDLE,\n generationStatusMessage: \"\",\n isIdle: true,\n});\n\n/**\n * The TamboThreadProvider is a React provider that provides a thread context\n * to the descendants of the provider.\n * @param props - The props for the TamboThreadProvider\n * @param props.children - The children to wrap\n * @returns The TamboThreadProvider component\n */\nexport const TamboThreadProvider: React.FC<PropsWithChildren> = ({\n children,\n}) => {\n const [threadMap, setThreadMap] = useState<Record<string, TamboThread>>({\n [PLACEHOLDER_THREAD.id]: PLACEHOLDER_THREAD,\n });\n const client = useTamboClient();\n const { componentList, toolRegistry, componentToolAssociations } =\n useTamboRegistry();\n const [inputValue, setInputValue] = useState(\"\");\n\n const [currentThreadId, setCurrentThreadId] = useState<string>(\n PLACEHOLDER_THREAD.id,\n );\n const currentThread: TamboThread | undefined = threadMap[currentThreadId];\n\n // Use existing messages from the current thread to avoid re-generating any components\n const currentMessageCache = useMemo(() => {\n const messageCache = new Map<string, TamboThreadMessage>();\n if (currentThread) {\n for (const message of currentThread.messages) {\n messageCache.set(message.id, message);\n }\n }\n return messageCache;\n }, [currentThread]);\n\n const fetchThread = useCallback(\n async (threadId: string) => {\n const thread = await client.beta.threads.retrieve(threadId);\n const threadWithRenderedComponents = {\n ...thread,\n messages: thread.messages.map((message) => {\n if (currentMessageCache.has(message.id)) {\n const renderedMessage = currentMessageCache.get(message.id);\n return {\n ...renderedMessage,\n ...message,\n };\n }\n if (message.component?.componentName) {\n const messageWithComponent = renderComponentIntoMessage(\n message,\n componentList,\n );\n return messageWithComponent;\n }\n return message;\n }),\n };\n\n setThreadMap((prevMap) => ({\n ...prevMap,\n [threadId]: threadWithRenderedComponents,\n }));\n },\n [client.beta.threads, componentList, currentMessageCache],\n );\n\n useEffect(() => {\n if (\n currentThreadId &&\n currentThreadId !== PLACEHOLDER_THREAD.id &&\n !threadMap[currentThreadId]\n ) {\n fetchThread(currentThreadId);\n }\n }, [currentThreadId, fetchThread, threadMap]);\n\n const addThreadMessage = useCallback(\n async (\n message: TamboThreadMessage,\n sendToServer = true,\n createdAt: string = new Date().toISOString(),\n ) => {\n if (!currentThread) {\n console.warn(\"Cannot add messages if we do not have a current thread\");\n return [];\n }\n const chatMessage: TamboThreadMessage & {\n additionalContext?: string;\n } = {\n ...message,\n additionalContext:\n message.role === \"user\" ? getClientContext() : undefined,\n createdAt,\n };\n const threadId = message.threadId;\n // optimistically update the thread in the local state\n setThreadMap((prevMap) => {\n if (!threadId) {\n return prevMap;\n }\n const prevMessages = prevMap[threadId]?.messages || [];\n const updatedMessages = [...prevMessages, chatMessage];\n return {\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n messages: updatedMessages,\n },\n };\n });\n\n if (sendToServer) {\n // TODO: if this fails, we need to revert the local state update\n await client.beta.threads.messages.create(message.threadId, {\n content: message.content,\n role: message.role,\n // additionalContext: chatMessage.additionalContext,\n });\n }\n return threadMap[threadId]?.messages || [];\n },\n [client.beta.threads.messages, currentThread, threadMap],\n );\n\n const updateThreadMessage = useCallback(\n async (\n id: string,\n message: TamboThreadMessage,\n sendToServer = true,\n createdAt: string = new Date().toISOString(),\n ) => {\n const chatMessage: TamboThreadMessage = {\n ...message,\n createdAt,\n };\n\n setThreadMap((prevMap) => {\n if (!message.threadId) {\n return prevMap;\n }\n const prevMessages = prevMap[message.threadId]?.messages || [];\n const updatedMessages = prevMessages.map((msg) => {\n if (msg.id === id) {\n return chatMessage;\n }\n return msg;\n });\n return {\n ...prevMap,\n [message.threadId]: {\n ...prevMap[message.threadId],\n messages: updatedMessages,\n },\n };\n });\n if (sendToServer) {\n // TODO: if this fails, we need to revert the local state update\n await client.beta.threads.messages.create(message.threadId, {\n content: message.content,\n role: message.role,\n // additionalContext: chatMessage.additionalContext,\n });\n }\n },\n [client.beta.threads.messages],\n );\n\n const deleteThreadMessage = useCallback(\n (messageId: string, threadId: string) => {\n if (!threadMap[threadId]) return;\n\n setThreadMap((prevMap) => ({\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n messages: prevMap[threadId].messages.filter(\n (msg) => msg.id !== messageId,\n ),\n },\n }));\n },\n [threadMap],\n );\n\n const startNewThread = useCallback(() => {\n setCurrentThreadId(PLACEHOLDER_THREAD.id);\n setThreadMap((prevMap) => {\n return {\n ...prevMap,\n [PLACEHOLDER_THREAD.id]: PLACEHOLDER_THREAD,\n };\n });\n }, []);\n\n const switchCurrentThread = useCallback(\n async (threadId: string, fetch = true) => {\n if (threadId === PLACEHOLDER_THREAD.id) {\n console.warn(\"Switching to placeholder thread, may be a bug.\");\n return;\n }\n\n setCurrentThreadId(threadId);\n if (!threadMap[threadId]) {\n setThreadMap((prevMap) => {\n return {\n ...prevMap,\n [threadId]: {\n ...prevMap[PLACEHOLDER_THREAD.id],\n id: threadId,\n },\n };\n });\n }\n if (fetch) {\n await fetchThread(threadId);\n }\n },\n [fetchThread, threadMap],\n );\n\n const updateThreadStatus = useCallback(\n (threadId: string, stage: GenerationStage, statusMessage?: string) => {\n setThreadMap((prevMap) => {\n return {\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n generationStage: stage,\n statusMessage: statusMessage,\n },\n };\n });\n },\n [],\n );\n\n const handleAdvanceStream = useCallback(\n async (\n stream: AsyncIterable<TamboAI.Beta.Threads.ThreadAdvanceResponse>,\n params: TamboAI.Beta.Threads.ThreadAdvanceParams,\n threadId: string,\n messageIdToRemove?: string,\n ): Promise<TamboThreadMessage> => {\n let finalMessage: TamboThreadMessage | undefined;\n let hasSetThreadId = false;\n let isFirstChunk = true;\n updateThreadStatus(threadId, GenerationStage.STREAMING_RESPONSE);\n\n for await (const chunk of stream) {\n if (isFirstChunk && messageIdToRemove) {\n deleteThreadMessage(messageIdToRemove, threadId);\n }\n isFirstChunk = false;\n\n if (chunk.responseMessageDto.toolCallRequest) {\n updateThreadStatus(threadId, GenerationStage.FETCHING_CONTEXT);\n const toolCallResponse = await handleToolCall(\n chunk.responseMessageDto,\n toolRegistry,\n );\n const toolCallResponseString =\n typeof toolCallResponse === \"string\"\n ? toolCallResponse\n : JSON.stringify(toolCallResponse);\n const toolCallResponseParams: TamboAI.Beta.Threads.ThreadAdvanceParams =\n {\n ...params,\n messageToAppend: {\n content: [{ type: \"text\", text: toolCallResponseString }],\n role: \"tool\",\n actionType: \"tool_response\",\n component: chunk.responseMessageDto.component,\n tool_call_id: chunk.responseMessageDto.tool_call_id,\n },\n };\n updateThreadStatus(threadId, GenerationStage.STREAMING_RESPONSE);\n const toolCallResponseStream = await advanceStream(\n client,\n toolCallResponseParams,\n chunk.responseMessageDto.threadId,\n );\n\n // Pass the current message's ID to be removed when the new stream starts, since we now know it is a tool call request message\n return await handleAdvanceStream(\n toolCallResponseStream,\n toolCallResponseParams,\n threadId,\n finalMessage?.id,\n );\n } else {\n if (\n !hasSetThreadId &&\n chunk.responseMessageDto.threadId &&\n chunk.responseMessageDto.threadId !== currentThread?.id\n ) {\n hasSetThreadId = true;\n switchCurrentThread(chunk.responseMessageDto.threadId, false);\n }\n\n if (!finalMessage) {\n finalMessage = chunk.responseMessageDto.component?.componentName\n ? renderComponentIntoMessage(\n chunk.responseMessageDto,\n componentList,\n )\n : chunk.responseMessageDto;\n addThreadMessage(finalMessage, false);\n } else {\n const previousId = finalMessage.id;\n finalMessage = chunk.responseMessageDto.component?.componentName\n ? renderComponentIntoMessage(\n chunk.responseMessageDto,\n componentList,\n )\n : chunk.responseMessageDto;\n updateThreadMessage(previousId, finalMessage, false);\n }\n }\n }\n\n updateThreadStatus(threadId, GenerationStage.COMPLETE);\n if (finalMessage) {\n await fetchThread(finalMessage.threadId);\n }\n return (\n finalMessage ?? {\n threadId: \"\",\n content: [{ type: \"text\", text: `Error processing stream` }],\n role: \"hydra\",\n createdAt: new Date().toISOString(),\n id: crypto.randomUUID(),\n componentState: {},\n }\n );\n },\n [\n addThreadMessage,\n client,\n componentList,\n currentThread?.id,\n deleteThreadMessage,\n fetchThread,\n switchCurrentThread,\n toolRegistry,\n updateThreadMessage,\n updateThreadStatus,\n ],\n );\n\n const sendThreadMessage = useCallback(\n async (\n message: string,\n options: {\n threadId?: string;\n streamResponse?: boolean;\n contextKey?: string;\n } = { threadId: PLACEHOLDER_THREAD.id },\n ): Promise<TamboThreadMessage> => {\n const { threadId = currentThread.id, streamResponse } = options;\n updateThreadStatus(threadId, GenerationStage.CHOOSING_COMPONENT);\n\n addThreadMessage(\n {\n content: [{ type: \"text\", text: message }],\n renderedComponent: null,\n role: \"user\",\n threadId: threadId,\n id: crypto.randomUUID(),\n createdAt: new Date().toISOString(),\n componentState: {},\n },\n false,\n );\n\n const availableComponents = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n const params: TamboAI.Beta.Threads.ThreadAdvanceParams = {\n messageToAppend: {\n content: [{ type: \"text\", text: message }],\n role: \"user\",\n },\n contextKey: options.contextKey,\n availableComponents: availableComponents,\n };\n\n if (streamResponse) {\n const advanceStreamResponse = await advanceStream(\n client,\n params,\n threadId === PLACEHOLDER_THREAD.id ? undefined : threadId,\n );\n return await handleAdvanceStream(\n advanceStreamResponse,\n params,\n threadId,\n );\n }\n let advanceResponse = await (threadId === PLACEHOLDER_THREAD.id\n ? client.beta.threads.advance(params)\n : client.beta.threads.advanceById(threadId, params));\n\n //handle tool calls\n while (advanceResponse.responseMessageDto.toolCallRequest) {\n updateThreadStatus(threadId, GenerationStage.FETCHING_CONTEXT);\n const toolCallResponse = await handleToolCall(\n advanceResponse.responseMessageDto,\n toolRegistry,\n );\n const toolResponseString =\n typeof toolCallResponse === \"string\"\n ? toolCallResponse\n : JSON.stringify(toolCallResponse);\n const toolCallResponseParams: TamboAI.Beta.Threads.ThreadAdvanceParams =\n {\n ...params,\n messageToAppend: {\n ...params.messageToAppend,\n content: [{ type: \"text\", text: toolResponseString }],\n role: \"tool\",\n actionType: \"tool_response\",\n component: advanceResponse.responseMessageDto.component,\n tool_call_id: advanceResponse.responseMessageDto.tool_call_id,\n },\n };\n updateThreadStatus(threadId, GenerationStage.HYDRATING_COMPONENT);\n advanceResponse = await client.beta.threads.advanceById(\n advanceResponse.responseMessageDto.threadId,\n toolCallResponseParams,\n );\n }\n\n const finalMessage = advanceResponse.responseMessageDto.component\n ?.componentName\n ? renderComponentIntoMessage(\n advanceResponse.responseMessageDto,\n componentList,\n )\n : advanceResponse.responseMessageDto;\n await switchCurrentThread(advanceResponse.responseMessageDto.threadId);\n updateThreadStatus(\n advanceResponse.responseMessageDto.threadId,\n GenerationStage.COMPLETE,\n );\n return finalMessage;\n },\n [\n componentList,\n toolRegistry,\n componentToolAssociations,\n currentThread.id,\n switchCurrentThread,\n addThreadMessage,\n client,\n updateThreadStatus,\n handleAdvanceStream,\n ],\n );\n\n return (\n <TamboThreadContext.Provider\n value={{\n thread: currentThread,\n switchCurrentThread,\n startNewThread,\n addThreadMessage,\n updateThreadMessage,\n inputValue,\n setInputValue,\n sendThreadMessage,\n generationStage: (currentThread?.generationStage ??\n GenerationStage.IDLE) as GenerationStage,\n generationStatusMessage: currentThread?.statusMessage ?? \"\",\n isIdle: isIdleStage(\n (currentThread?.generationStage ??\n GenerationStage.IDLE) as GenerationStage,\n ),\n }}\n >\n {children}\n </TamboThreadContext.Provider>\n );\n};\n\n/**\n * The useTamboThread hook provides access to the current thread context\n * to the descendants of the TamboThreadProvider.\n * @returns All state and actions for the current thread\n */\nexport const useTamboThread = () => {\n const context = useContext(TamboThreadContext);\n if (context === undefined) {\n throw new Error(\"useTamboThread must be used within a TamboThreadProvider\");\n }\n return context;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"tambo-thread-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-thread-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport TamboAI, { advanceStream } from \"@tambo-ai/typescript-sdk\";\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n GenerationStage,\n isIdleStage,\n TamboThreadMessage,\n} from \"../model/generate-component-response\";\nimport { TamboThread } from \"../model/tambo-thread\";\nimport { renderComponentIntoMessage } from \"../util/generate-component\";\nimport { getAvailableComponents, getClientContext } from \"../util/registry\";\nimport { handleToolCall } from \"../util/tool-caller\";\nimport { useTamboClient } from \"./tambo-client-provider\";\nimport { useTamboRegistry } from \"./tambo-registry-provider\";\n\nexport interface TamboThreadContextProps {\n /** The current thread */\n thread: TamboThread;\n /** Switch to a different thread */\n switchCurrentThread: (threadId: string, fetch?: boolean) => void;\n /** Start a new thread */\n startNewThread: () => void;\n /** Add a message to the current thread */\n addThreadMessage: (\n message: TamboThreadMessage,\n sendToServer: boolean,\n ) => Promise<TamboAI.Beta.Threads.ThreadMessage[]>;\n /** Update a message in the current thread */\n updateThreadMessage: (\n id: string,\n message: TamboThreadMessage,\n sendToServer: boolean,\n ) => Promise<void>;\n /** The input value of the current thread */\n inputValue: string;\n /** Set the input value of the current thread */\n setInputValue: (value: string) => void;\n /** Send a message to the current thread */\n sendThreadMessage: (\n message: string,\n options: {\n threadId?: string;\n streamResponse?: boolean;\n contextKey?: string;\n },\n ) => Promise<TamboThreadMessage>;\n /** The generation stage of the current thread - updated as the thread progresses */\n generationStage: GenerationStage;\n /** The generation status message of the current thread - updated as the thread progresses */\n generationStatusMessage: string;\n /** Whether the thread is idle */\n isIdle: boolean;\n}\n\n/**\n * This is a stub entry for when the thread is not yet created, the first time\n * the user sends a message\n *\n * Note that the consumer needs to be careful never to send `PLACEHOLDER_THREAD.id` to the server,\n * as this doesn't really exist on the server side.\n */\nexport const PLACEHOLDER_THREAD: TamboThread = {\n id: \"placeholder\",\n messages: [],\n createdAt: \"\",\n projectId: \"\",\n updatedAt: \"\",\n metadata: {},\n};\n\nexport const TamboThreadContext = createContext<TamboThreadContextProps>({\n thread: PLACEHOLDER_THREAD,\n /**\n *\n */\n switchCurrentThread: () => {\n throw new Error(\"switchCurrentThread not implemented\");\n },\n /**\n *\n */\n startNewThread: () => {\n throw new Error(\"startNewThread not implemented\");\n },\n /**\n *\n */\n addThreadMessage: () => {\n throw new Error(\"updateThreadMessageHistory not implemented\");\n },\n inputValue: \"\",\n /**\n *\n */\n setInputValue: () => {\n throw new Error(\"setInputValue not implemented\");\n },\n /**\n *\n */\n updateThreadMessage: () => {\n throw new Error(\"updateThreadMessage not implemented\");\n },\n /**\n *\n */\n sendThreadMessage: () => {\n throw new Error(\"advance not implemented\");\n },\n generationStage: GenerationStage.IDLE,\n generationStatusMessage: \"\",\n isIdle: true,\n});\n\n/**\n * The TamboThreadProvider is a React provider that provides a thread context\n * to the descendants of the provider.\n * @param props - The props for the TamboThreadProvider\n * @param props.children - The children to wrap\n * @returns The TamboThreadProvider component\n */\nexport const TamboThreadProvider: React.FC<PropsWithChildren> = ({\n children,\n}) => {\n const [threadMap, setThreadMap] = useState<Record<string, TamboThread>>({\n [PLACEHOLDER_THREAD.id]: PLACEHOLDER_THREAD,\n });\n const client = useTamboClient();\n const { componentList, toolRegistry, componentToolAssociations } =\n useTamboRegistry();\n const [inputValue, setInputValue] = useState(\"\");\n\n const [currentThreadId, setCurrentThreadId] = useState<string>(\n PLACEHOLDER_THREAD.id,\n );\n const currentThread: TamboThread | undefined = threadMap[currentThreadId];\n\n // Use existing messages from the current thread to avoid re-generating any components\n const currentMessageCache = useMemo(() => {\n const messageCache = new Map<string, TamboThreadMessage>();\n if (currentThread) {\n for (const message of currentThread.messages) {\n messageCache.set(message.id, message);\n }\n }\n return messageCache;\n }, [currentThread]);\n\n const fetchThread = useCallback(\n async (threadId: string) => {\n const thread = await client.beta.threads.retrieve(threadId);\n const threadWithRenderedComponents = {\n ...thread,\n messages: thread.messages.map((message) => {\n if (currentMessageCache.has(message.id)) {\n const renderedMessage = currentMessageCache.get(message.id);\n return {\n ...renderedMessage,\n ...message,\n };\n }\n if (message.component?.componentName) {\n const messageWithComponent = renderComponentIntoMessage(\n message,\n componentList,\n );\n return messageWithComponent;\n }\n return message;\n }),\n };\n\n setThreadMap((prevMap) => {\n const updatedThreadMap = {\n ...prevMap,\n [threadId]: threadWithRenderedComponents,\n };\n return updatedThreadMap;\n });\n },\n [client.beta.threads, componentList, currentMessageCache],\n );\n\n useEffect(() => {\n if (\n currentThreadId &&\n currentThreadId !== PLACEHOLDER_THREAD.id &&\n !threadMap[currentThreadId]\n ) {\n fetchThread(currentThreadId);\n }\n }, [currentThreadId, fetchThread, threadMap]);\n\n const addThreadMessage = useCallback(\n async (\n message: TamboThreadMessage,\n sendToServer = true,\n createdAt: string = new Date().toISOString(),\n ) => {\n if (!currentThread) {\n console.warn(\"Cannot add messages if we do not have a current thread\");\n return [];\n }\n const chatMessage: TamboThreadMessage & {\n additionalContext?: string;\n } = {\n ...message,\n additionalContext:\n message.role === \"user\" ? getClientContext() : undefined,\n createdAt,\n };\n const threadId = message.threadId;\n // optimistically update the thread in the local state\n setThreadMap((prevMap) => {\n if (!threadId) {\n return prevMap;\n }\n const prevMessages = prevMap[threadId]?.messages || [];\n const updatedMessages = [...prevMessages, chatMessage];\n\n const updatedThreadMap = {\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n messages: updatedMessages,\n },\n };\n return updatedThreadMap;\n });\n\n if (sendToServer) {\n // TODO: if this fails, we need to revert the local state update\n await client.beta.threads.messages.create(message.threadId, {\n content: message.content,\n role: message.role,\n // additionalContext: chatMessage.additionalContext,\n });\n }\n return threadMap[threadId]?.messages || [];\n },\n [client.beta.threads.messages, currentThread, threadMap],\n );\n\n const updateThreadMessage = useCallback(\n async (\n id: string,\n message: TamboThreadMessage,\n sendToServer = true,\n createdAt: string = new Date().toISOString(),\n ) => {\n const chatMessage: TamboThreadMessage = {\n ...message,\n createdAt,\n };\n\n setThreadMap((prevMap) => {\n if (!message.threadId) {\n return prevMap;\n }\n const prevMessages = prevMap[message.threadId]?.messages || [];\n const updatedMessages = prevMessages.map((msg) => {\n if (msg.id === id) {\n return chatMessage;\n }\n return msg;\n });\n return {\n ...prevMap,\n [message.threadId]: {\n ...prevMap[message.threadId],\n messages: updatedMessages,\n },\n };\n });\n if (sendToServer) {\n // TODO: if this fails, we need to revert the local state update\n await client.beta.threads.messages.create(message.threadId, {\n content: message.content,\n role: message.role,\n // additionalContext: chatMessage.additionalContext,\n });\n }\n },\n [client.beta.threads.messages],\n );\n\n const deleteThreadMessage = useCallback(\n (messageId: string, threadId: string) => {\n if (!threadMap[threadId]) return;\n\n setThreadMap((prevMap) => ({\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n messages: prevMap[threadId].messages.filter(\n (msg) => msg.id !== messageId,\n ),\n },\n }));\n },\n [threadMap],\n );\n\n const startNewThread = useCallback(() => {\n setCurrentThreadId(PLACEHOLDER_THREAD.id);\n setThreadMap((prevMap) => {\n return {\n ...prevMap,\n [PLACEHOLDER_THREAD.id]: PLACEHOLDER_THREAD,\n };\n });\n }, []);\n\n const switchCurrentThread = useCallback(\n async (threadId: string, fetch = true) => {\n if (threadId === PLACEHOLDER_THREAD.id) {\n console.warn(\"Switching to placeholder thread, may be a bug.\");\n return;\n }\n setCurrentThreadId(threadId);\n setThreadMap((prevMap) => {\n if (prevMap[threadId]) {\n return prevMap;\n }\n // If this is a new thread, add placeholder thread messages to the thread\n const updatedThreadMap = {\n ...prevMap,\n [threadId]: {\n ...prevMap[PLACEHOLDER_THREAD.id],\n id: threadId,\n },\n };\n return updatedThreadMap;\n });\n if (fetch) {\n await fetchThread(threadId);\n }\n },\n [fetchThread, threadMap],\n );\n\n const updateThreadStatus = useCallback(\n (threadId: string, stage: GenerationStage, statusMessage?: string) => {\n setThreadMap((prevMap) => {\n const updatedThreadMap = {\n ...prevMap,\n [threadId]: {\n ...prevMap[threadId],\n generationStage: stage,\n statusMessage: statusMessage,\n },\n };\n return updatedThreadMap;\n });\n },\n [],\n );\n\n const handleAdvanceStream = useCallback(\n async (\n stream: AsyncIterable<TamboAI.Beta.Threads.ThreadAdvanceResponse>,\n params: TamboAI.Beta.Threads.ThreadAdvanceParams,\n threadId: string,\n messageIdToRemove?: string,\n ): Promise<TamboThreadMessage> => {\n let finalMessage: TamboThreadMessage | undefined;\n let hasSetThreadId = false;\n let isFirstChunk = true;\n updateThreadStatus(threadId, GenerationStage.STREAMING_RESPONSE);\n\n for await (const chunk of stream) {\n if (isFirstChunk && messageIdToRemove) {\n deleteThreadMessage(messageIdToRemove, threadId);\n }\n isFirstChunk = false;\n\n if (chunk.responseMessageDto.toolCallRequest) {\n updateThreadStatus(\n chunk.responseMessageDto.threadId,\n GenerationStage.FETCHING_CONTEXT,\n );\n const toolCallResponse = await handleToolCall(\n chunk.responseMessageDto,\n toolRegistry,\n );\n const toolCallResponseString =\n typeof toolCallResponse === \"string\"\n ? toolCallResponse\n : JSON.stringify(toolCallResponse);\n const toolCallResponseParams: TamboAI.Beta.Threads.ThreadAdvanceParams =\n {\n ...params,\n messageToAppend: {\n content: [{ type: \"text\", text: toolCallResponseString }],\n role: \"tool\",\n actionType: \"tool_response\",\n component: chunk.responseMessageDto.component,\n tool_call_id: chunk.responseMessageDto.tool_call_id,\n },\n };\n updateThreadStatus(\n chunk.responseMessageDto.threadId,\n GenerationStage.STREAMING_RESPONSE,\n );\n const toolCallResponseStream = await advanceStream(\n client,\n toolCallResponseParams,\n chunk.responseMessageDto.threadId,\n );\n\n return await handleAdvanceStream(\n toolCallResponseStream,\n toolCallResponseParams,\n chunk.responseMessageDto.threadId,\n );\n } else {\n if (\n !hasSetThreadId &&\n chunk.responseMessageDto.threadId &&\n chunk.responseMessageDto.threadId !== currentThread?.id\n ) {\n hasSetThreadId = true;\n switchCurrentThread(chunk.responseMessageDto.threadId, false);\n }\n\n if (!finalMessage) {\n finalMessage = chunk.responseMessageDto.component?.componentName\n ? renderComponentIntoMessage(\n chunk.responseMessageDto,\n componentList,\n )\n : chunk.responseMessageDto;\n addThreadMessage(finalMessage, false);\n } else {\n const previousId = finalMessage.id;\n finalMessage = chunk.responseMessageDto.component?.componentName\n ? renderComponentIntoMessage(\n chunk.responseMessageDto,\n componentList,\n )\n : chunk.responseMessageDto;\n updateThreadMessage(previousId, finalMessage, false);\n }\n }\n }\n\n updateThreadStatus(\n finalMessage?.threadId ?? threadId,\n GenerationStage.COMPLETE,\n );\n return (\n finalMessage ?? {\n threadId: \"\",\n content: [{ type: \"text\", text: `Error processing stream` }],\n role: \"hydra\",\n createdAt: new Date().toISOString(),\n id: crypto.randomUUID(),\n componentState: {},\n }\n );\n },\n [\n addThreadMessage,\n client,\n componentList,\n currentThread?.id,\n deleteThreadMessage,\n fetchThread,\n switchCurrentThread,\n toolRegistry,\n updateThreadMessage,\n updateThreadStatus,\n ],\n );\n\n const sendThreadMessage = useCallback(\n async (\n message: string,\n options: {\n threadId?: string;\n streamResponse?: boolean;\n contextKey?: string;\n } = { threadId: PLACEHOLDER_THREAD.id },\n ): Promise<TamboThreadMessage> => {\n const { threadId = currentThread.id, streamResponse } = options;\n updateThreadStatus(threadId, GenerationStage.CHOOSING_COMPONENT);\n\n addThreadMessage(\n {\n content: [{ type: \"text\", text: message }],\n renderedComponent: null,\n role: \"user\",\n threadId: threadId,\n id: crypto.randomUUID(),\n createdAt: new Date().toISOString(),\n componentState: {},\n },\n false,\n );\n\n const availableComponents = getAvailableComponents(\n componentList,\n toolRegistry,\n componentToolAssociations,\n );\n const params: TamboAI.Beta.Threads.ThreadAdvanceParams = {\n messageToAppend: {\n content: [{ type: \"text\", text: message }],\n role: \"user\",\n },\n contextKey: options.contextKey,\n availableComponents: availableComponents,\n };\n\n if (streamResponse) {\n const advanceStreamResponse = await advanceStream(\n client,\n params,\n threadId === PLACEHOLDER_THREAD.id ? undefined : threadId,\n );\n return await handleAdvanceStream(\n advanceStreamResponse,\n params,\n threadId,\n );\n }\n let advanceResponse = await (threadId === PLACEHOLDER_THREAD.id\n ? client.beta.threads.advance(params)\n : client.beta.threads.advanceById(threadId, params));\n\n //handle tool calls\n while (advanceResponse.responseMessageDto.toolCallRequest) {\n updateThreadStatus(threadId, GenerationStage.FETCHING_CONTEXT);\n const toolCallResponse = await handleToolCall(\n advanceResponse.responseMessageDto,\n toolRegistry,\n );\n const toolResponseString =\n typeof toolCallResponse === \"string\"\n ? toolCallResponse\n : JSON.stringify(toolCallResponse);\n const toolCallResponseParams: TamboAI.Beta.Threads.ThreadAdvanceParams =\n {\n ...params,\n messageToAppend: {\n ...params.messageToAppend,\n content: [{ type: \"text\", text: toolResponseString }],\n role: \"tool\",\n actionType: \"tool_response\",\n component: advanceResponse.responseMessageDto.component,\n tool_call_id: advanceResponse.responseMessageDto.tool_call_id,\n },\n };\n updateThreadStatus(threadId, GenerationStage.HYDRATING_COMPONENT);\n advanceResponse = await client.beta.threads.advanceById(\n advanceResponse.responseMessageDto.threadId,\n toolCallResponseParams,\n );\n }\n\n const finalMessage = advanceResponse.responseMessageDto.component\n ?.componentName\n ? renderComponentIntoMessage(\n advanceResponse.responseMessageDto,\n componentList,\n )\n : advanceResponse.responseMessageDto;\n await switchCurrentThread(advanceResponse.responseMessageDto.threadId);\n updateThreadStatus(\n advanceResponse.responseMessageDto.threadId,\n GenerationStage.COMPLETE,\n );\n return finalMessage;\n },\n [\n componentList,\n toolRegistry,\n componentToolAssociations,\n currentThread.id,\n switchCurrentThread,\n addThreadMessage,\n client,\n updateThreadStatus,\n handleAdvanceStream,\n ],\n );\n\n return (\n <TamboThreadContext.Provider\n value={{\n thread: currentThread,\n switchCurrentThread,\n startNewThread,\n addThreadMessage,\n updateThreadMessage,\n inputValue,\n setInputValue,\n sendThreadMessage,\n generationStage: (currentThread?.generationStage ??\n GenerationStage.IDLE) as GenerationStage,\n generationStatusMessage: currentThread?.statusMessage ?? \"\",\n isIdle: isIdleStage(\n (currentThread?.generationStage ??\n GenerationStage.IDLE) as GenerationStage,\n ),\n }}\n >\n {children}\n </TamboThreadContext.Provider>\n );\n};\n\n/**\n * The useTamboThread hook provides access to the current thread context\n * to the descendants of the TamboThreadProvider.\n * @returns All state and actions for the current thread\n */\nexport const useTamboThread = () => {\n const context = useContext(TamboThreadContext);\n if (context === undefined) {\n throw new Error(\"useTamboThread must be used within a TamboThreadProvider\");\n }\n return context;\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTests.d.ts","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":"AAAA,OAAO,qCAAqC,CAAC;AAC7C,OAAO,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("@tambo-ai/typescript-sdk/shims/node");
|
|
4
|
+
require("@testing-library/jest-dom");
|
|
5
|
+
// Mock Date.now() to return a fixed timestamp for consistent testing
|
|
6
|
+
const mockDate = new Date(2025, 0, 5, 12, 32, 58, 936);
|
|
7
|
+
global.Date.now = jest.fn(() => mockDate.getTime());
|
|
8
|
+
//# sourceMappingURL=setupTests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setupTests.js","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":";;AAAA,+CAA6C;AAC7C,qCAAmC;AAEnC,qEAAqE;AACrE,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;AACvD,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC","sourcesContent":["import \"@tambo-ai/typescript-sdk/shims/node\";\nimport \"@testing-library/jest-dom\";\n\n// Mock Date.now() to return a fixed timestamp for consistent testing\nconst mockDate = new Date(2025, 0, 5, 12, 32, 58, 936);\nglobal.Date.now = jest.fn(() => mockDate.getTime());\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TamboComponent } from "../providers";
|
|
2
|
+
/**
|
|
3
|
+
* Serializes the registry for testing purposes
|
|
4
|
+
* @param mockRegistry - The registry to serialize
|
|
5
|
+
* @returns The serialized registry
|
|
6
|
+
*/
|
|
7
|
+
export declare function serializeRegistry(mockRegistry: TamboComponent[]): {
|
|
8
|
+
props: import("zod-to-json-schema").JsonSchema7Type & {
|
|
9
|
+
$schema?: string | undefined;
|
|
10
|
+
definitions?: {
|
|
11
|
+
[key: string]: import("zod-to-json-schema").JsonSchema7Type;
|
|
12
|
+
} | undefined;
|
|
13
|
+
};
|
|
14
|
+
contextTools: {
|
|
15
|
+
parameters: any;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}[] | undefined;
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
propsDefinition?: any;
|
|
22
|
+
loadingComponent?: import("react").ComponentType<any>;
|
|
23
|
+
}[];
|
|
24
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/testing/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,cAAc,EAAE;;;;;;;;;;;;;;;;IA0B/D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.serializeRegistry = serializeRegistry;
|
|
7
|
+
const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
|
|
8
|
+
/**
|
|
9
|
+
* Serializes the registry for testing purposes
|
|
10
|
+
* @param mockRegistry - The registry to serialize
|
|
11
|
+
* @returns The serialized registry
|
|
12
|
+
*/
|
|
13
|
+
function serializeRegistry(mockRegistry) {
|
|
14
|
+
return mockRegistry.map(({ component: _component, propsSchema, associatedTools, ...componentEntry }) => ({
|
|
15
|
+
...componentEntry,
|
|
16
|
+
props: (0, zod_to_json_schema_1.default)(propsSchema),
|
|
17
|
+
contextTools: associatedTools?.map(({ toolSchema, tool: _tool, ...toolEntry }) => ({
|
|
18
|
+
...toolEntry,
|
|
19
|
+
parameters: toolSchema
|
|
20
|
+
.parameters()
|
|
21
|
+
.items.map((p, index) => ({
|
|
22
|
+
name: `param${index + 1}`,
|
|
23
|
+
schema: (0, zod_to_json_schema_1.default)(p),
|
|
24
|
+
isRequired: true,
|
|
25
|
+
description: p.description,
|
|
26
|
+
type: (0, zod_to_json_schema_1.default)(p).type,
|
|
27
|
+
})),
|
|
28
|
+
})),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/testing/tools.ts"],"names":[],"mappings":";;;;;AASA,8CA0BC;AAlCD,4EAAiD;AAGjD;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,YAA8B;IAC9D,OAAO,YAAY,CAAC,GAAG,CACrB,CAAC,EACC,SAAS,EAAE,UAAU,EACrB,WAAW,EACX,eAAe,EACf,GAAG,cAAc,EAClB,EAAE,EAAE,CAAC,CAAC;QACL,GAAG,cAAc;QACjB,KAAK,EAAE,IAAA,4BAAe,EAAC,WAA2B,CAAC;QACnD,YAAY,EAAE,eAAe,EAAE,GAAG,CAChC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9C,GAAG,SAAS;YACZ,UAAU,EAAE,UAAU;iBACnB,UAAU,EAAE;iBACZ,KAAK,CAAC,GAAG,CAAC,CAAC,CAAe,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC;gBAC9C,IAAI,EAAE,QAAQ,KAAK,GAAG,CAAC,EAAE;gBACzB,MAAM,EAAE,IAAA,4BAAe,EAAC,CAAC,CAAC;gBAC1B,UAAU,EAAE,IAAI;gBAChB,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,IAAI,EAAG,IAAA,4BAAe,EAAC,CAAC,CAAS,CAAC,IAAI;aACvC,CAAC,CAAC;SACN,CAAC,CACH;KACF,CAAC,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { z } from \"zod\";\nimport zodToJsonSchema from \"zod-to-json-schema\";\nimport { TamboComponent } from \"../providers\";\n\n/**\n * Serializes the registry for testing purposes\n * @param mockRegistry - The registry to serialize\n * @returns The serialized registry\n */\nexport function serializeRegistry(mockRegistry: TamboComponent[]) {\n return mockRegistry.map(\n ({\n component: _component,\n propsSchema,\n associatedTools,\n ...componentEntry\n }) => ({\n ...componentEntry,\n props: zodToJsonSchema(propsSchema as z.ZodTypeAny),\n contextTools: associatedTools?.map(\n ({ toolSchema, tool: _tool, ...toolEntry }) => ({\n ...toolEntry,\n parameters: toolSchema\n .parameters()\n .items.map((p: z.ZodTypeAny, index: number) => ({\n name: `param${index + 1}`,\n schema: zodToJsonSchema(p),\n isRequired: true,\n description: p.description,\n type: (zodToJsonSchema(p) as any).type,\n })),\n }),\n ),\n }),\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/testing/types.ts"],"names":[],"mappings":"","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { DeepPartial } from \"ts-essentials\";\n\nexport type PartialTamboAI = DeepPartial<TamboAI>;\n"]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { QueryClient } from "@tanstack/react-query";
|
|
2
2
|
import { act, renderHook } from "@testing-library/react";
|
|
3
|
-
import { useTamboClient } from "../../providers/tambo-client-provider";
|
|
3
|
+
import { useTamboClient, useTamboQueryClient, } from "../../providers/tambo-client-provider";
|
|
4
4
|
import { useTambo } from "../../providers/tambo-provider";
|
|
5
|
-
import { useTamboThread } from "../../providers/tambo-thread-provider";
|
|
6
|
-
import { useTamboQuery } from "../react-query-hooks";
|
|
5
|
+
import { useTamboThread, } from "../../providers/tambo-thread-provider";
|
|
6
|
+
import { useTamboMutation, useTamboQuery } from "../react-query-hooks";
|
|
7
7
|
import { useTamboSuggestions } from "../use-suggestions";
|
|
8
8
|
import { useTamboThreadInput } from "../use-thread-input";
|
|
9
9
|
// Mock the required providers
|
|
10
10
|
jest.mock("../../providers/tambo-client-provider", () => ({
|
|
11
11
|
useTamboClient: jest.fn(),
|
|
12
|
-
useTamboQueryClient: jest.fn()
|
|
12
|
+
useTamboQueryClient: jest.fn(),
|
|
13
13
|
}));
|
|
14
14
|
jest.mock("../../providers/tambo-provider", () => ({ useTambo: jest.fn() }));
|
|
15
15
|
jest.mock("../../providers/tambo-thread-provider", () => ({
|
|
@@ -19,12 +19,7 @@ jest.mock("../use-thread-input", () => ({ useTamboThreadInput: jest.fn() }));
|
|
|
19
19
|
// Mock the react-query-hooks
|
|
20
20
|
jest.mock("../react-query-hooks", () => ({
|
|
21
21
|
useTamboQuery: jest.fn(),
|
|
22
|
-
|
|
23
|
-
mutateAsync: mutationFn,
|
|
24
|
-
isLoading: false,
|
|
25
|
-
isError: false,
|
|
26
|
-
error: null,
|
|
27
|
-
})),
|
|
22
|
+
useTamboMutation: jest.fn(),
|
|
28
23
|
}));
|
|
29
24
|
describe("useTamboSuggestions", () => {
|
|
30
25
|
const mockSuggestions = [
|
|
@@ -42,23 +37,39 @@ describe("useTamboSuggestions", () => {
|
|
|
42
37
|
},
|
|
43
38
|
];
|
|
44
39
|
beforeEach(() => {
|
|
45
|
-
jest.
|
|
40
|
+
jest.mocked(useTamboQueryClient).mockReturnValue(new QueryClient());
|
|
41
|
+
jest.mocked(useTamboMutation).mockImplementation(({ mutationFn }) => ({
|
|
42
|
+
mutateAsync: mutationFn,
|
|
43
|
+
isLoading: false,
|
|
44
|
+
isError: false,
|
|
45
|
+
error: null,
|
|
46
|
+
}));
|
|
46
47
|
// Setup default mock implementations
|
|
47
|
-
useTamboClient.mockReturnValue({
|
|
48
|
+
jest.mocked(useTamboClient).mockReturnValue({
|
|
48
49
|
beta: { threads: { suggestions: { generate: jest.fn() } } },
|
|
49
50
|
});
|
|
50
|
-
useTambo.mockReturnValue({
|
|
51
|
-
|
|
51
|
+
jest.mocked(useTambo).mockReturnValue({
|
|
52
|
+
sendThreadMessage: jest.fn(),
|
|
53
|
+
});
|
|
54
|
+
jest.mocked(useTamboThread).mockReturnValue({
|
|
52
55
|
thread: {
|
|
53
56
|
id: "test-thread-id",
|
|
54
57
|
messages: [
|
|
55
|
-
{
|
|
58
|
+
{
|
|
59
|
+
id: "test-message-id",
|
|
60
|
+
role: "hydra",
|
|
61
|
+
content: [{ type: "text", text: "Test message" }],
|
|
62
|
+
},
|
|
56
63
|
],
|
|
57
64
|
},
|
|
58
65
|
});
|
|
59
|
-
useTamboThreadInput.mockReturnValue({
|
|
66
|
+
jest.mocked(useTamboThreadInput).mockReturnValue({
|
|
67
|
+
setValue: jest.fn(),
|
|
68
|
+
value: "",
|
|
69
|
+
submit: jest.fn(),
|
|
70
|
+
});
|
|
60
71
|
// Default query mock returns empty array
|
|
61
|
-
useTamboQuery.mockReturnValue({
|
|
72
|
+
jest.mocked(useTamboQuery).mockReturnValue({
|
|
62
73
|
data: [],
|
|
63
74
|
isLoading: false,
|
|
64
75
|
isError: false,
|
|
@@ -72,11 +83,30 @@ describe("useTamboSuggestions", () => {
|
|
|
72
83
|
});
|
|
73
84
|
it("should generate suggestions when latest message is from Tambo", async () => {
|
|
74
85
|
const mockGenerate = jest.fn().mockResolvedValue(mockSuggestions);
|
|
75
|
-
useTamboClient.mockReturnValue({
|
|
76
|
-
beta: {
|
|
86
|
+
jest.mocked(useTamboClient).mockReturnValue({
|
|
87
|
+
beta: {
|
|
88
|
+
threads: {
|
|
89
|
+
suggestions: {
|
|
90
|
+
generate: mockGenerate,
|
|
91
|
+
list: jest.fn(),
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
jest.mocked(useTamboThread).mockReturnValue({
|
|
97
|
+
thread: {
|
|
98
|
+
id: "test-thread-id",
|
|
99
|
+
messages: [
|
|
100
|
+
{
|
|
101
|
+
id: "test-message-id",
|
|
102
|
+
role: "assistant",
|
|
103
|
+
content: [{ type: "text", text: "Test message" }],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
77
107
|
});
|
|
78
108
|
// Mock the query result to return the mock suggestions
|
|
79
|
-
useTamboQuery.mockReturnValue({
|
|
109
|
+
jest.mocked(useTamboQuery).mockReturnValue({
|
|
80
110
|
data: mockSuggestions,
|
|
81
111
|
isLoading: false,
|
|
82
112
|
isError: false,
|
|
@@ -93,15 +123,26 @@ describe("useTamboSuggestions", () => {
|
|
|
93
123
|
});
|
|
94
124
|
it("should not generate suggestions when latest message is not from Tambo", async () => {
|
|
95
125
|
const mockGenerate = jest.fn();
|
|
96
|
-
useTamboClient.mockReturnValue({
|
|
97
|
-
beta: {
|
|
126
|
+
jest.mocked(useTamboClient).mockReturnValue({
|
|
127
|
+
beta: {
|
|
128
|
+
threads: {
|
|
129
|
+
suggestions: {
|
|
130
|
+
generate: mockGenerate,
|
|
131
|
+
list: jest.fn(),
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
98
135
|
});
|
|
99
136
|
// Mock the thread to have a non-Tambo message
|
|
100
|
-
useTamboThread.mockReturnValue({
|
|
137
|
+
jest.mocked(useTamboThread).mockReturnValue({
|
|
101
138
|
thread: {
|
|
102
139
|
id: "test-thread-id",
|
|
103
140
|
messages: [
|
|
104
|
-
{
|
|
141
|
+
{
|
|
142
|
+
id: "test-message-id",
|
|
143
|
+
role: "user",
|
|
144
|
+
content: [{ type: "text", text: "Test message" }],
|
|
145
|
+
},
|
|
105
146
|
],
|
|
106
147
|
},
|
|
107
148
|
});
|
|
@@ -115,8 +156,10 @@ describe("useTamboSuggestions", () => {
|
|
|
115
156
|
});
|
|
116
157
|
it("should accept a suggestion and update input value", async () => {
|
|
117
158
|
const mockSetValue = jest.fn();
|
|
118
|
-
useTamboThreadInput.mockReturnValue({
|
|
159
|
+
jest.mocked(useTamboThreadInput).mockReturnValue({
|
|
119
160
|
setValue: mockSetValue,
|
|
161
|
+
value: "",
|
|
162
|
+
submit: jest.fn(),
|
|
120
163
|
});
|
|
121
164
|
const { result } = renderHook(() => useTamboSuggestions());
|
|
122
165
|
await act(async () => {
|
|
@@ -130,7 +173,7 @@ describe("useTamboSuggestions", () => {
|
|
|
130
173
|
});
|
|
131
174
|
it("should accept a suggestion and submit it", async () => {
|
|
132
175
|
const mockSendThreadMessage = jest.fn();
|
|
133
|
-
useTambo.mockReturnValue({
|
|
176
|
+
jest.mocked(useTambo).mockReturnValue({
|
|
134
177
|
sendThreadMessage: mockSendThreadMessage,
|
|
135
178
|
});
|
|
136
179
|
const { result } = renderHook(() => useTamboSuggestions());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-suggestions.test.js","sourceRoot":"","sources":["../../../src/hooks/__tests__/use-suggestions.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { QueryClient } from \"@tanstack/react-query\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport { useTamboClient } from \"../../providers/tambo-client-provider\";\nimport { useTambo } from \"../../providers/tambo-provider\";\nimport { useTamboThread } from \"../../providers/tambo-thread-provider\";\nimport { useTamboQuery } from \"../react-query-hooks\";\nimport { useTamboSuggestions } from \"../use-suggestions\";\nimport { useTamboThreadInput } from \"../use-thread-input\";\n\n// Mock the required providers\njest.mock(\"../../providers/tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn().mockReturnValue(new QueryClient()),\n}));\n\njest.mock(\"../../providers/tambo-provider\", () => ({ useTambo: jest.fn() }));\n\njest.mock(\"../../providers/tambo-thread-provider\", () => ({\n useTamboThread: jest.fn(),\n}));\n\njest.mock(\"../use-thread-input\", () => ({ useTamboThreadInput: jest.fn() }));\n\n// Mock the react-query-hooks\njest.mock(\"../react-query-hooks\", () => ({\n useTamboQuery: jest.fn(),\n useTamboMutationResult: jest.fn().mockImplementation(({ mutationFn }) => ({\n mutateAsync: mutationFn,\n isLoading: false,\n isError: false,\n error: null,\n })),\n}));\n\ndescribe(\"useTamboSuggestions\", () => {\n const mockSuggestions: TamboAI.Beta.Threads.Suggestion[] = [\n {\n id: \"suggestion-1\",\n messageId: \"test-message-id\",\n title: \"Test Suggestion 1\",\n detailedSuggestion: \"Test suggestion 1\",\n },\n {\n id: \"suggestion-2\",\n messageId: \"test-message-id\",\n title: \"Test Suggestion 2\",\n detailedSuggestion: \"Test suggestion 2\",\n },\n ];\n\n beforeEach(() => {\n jest.clearAllMocks();\n // Setup default mock implementations\n (useTamboClient as jest.Mock).mockReturnValue({\n beta: { threads: { suggestions: { generate: jest.fn() } } },\n });\n (useTambo as jest.Mock).mockReturnValue({ sendThreadMessage: jest.fn() });\n (useTamboThread as jest.Mock).mockReturnValue({\n thread: {\n id: \"test-thread-id\",\n messages: [\n { id: \"test-message-id\", role: \"hydra\", content: \"Test message\" },\n ],\n },\n });\n (useTamboThreadInput as jest.Mock).mockReturnValue({ setValue: jest.fn() });\n // Default query mock returns empty array\n (useTamboQuery as jest.Mock).mockReturnValue({\n data: [],\n isLoading: false,\n isError: false,\n error: null,\n });\n });\n\n it(\"should initialize with empty suggestions and no selected suggestion\", () => {\n const { result } = renderHook(() => useTamboSuggestions());\n\n expect(result.current.suggestions).toEqual([]);\n expect(result.current.selectedSuggestionId).toBeNull();\n });\n\n it(\"should generate suggestions when latest message is from Tambo\", async () => {\n const mockGenerate = jest.fn().mockResolvedValue(mockSuggestions);\n (useTamboClient as jest.Mock).mockReturnValue({\n beta: { threads: { suggestions: { generate: mockGenerate } } },\n });\n\n // Mock the query result to return the mock suggestions\n (useTamboQuery as jest.Mock).mockReturnValue({\n data: mockSuggestions,\n isLoading: false,\n isError: false,\n error: null,\n });\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n // Wait for the effect to run\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n\n // Since we're mocking useTamboQuery to return the suggestions directly,\n // the generate function won't be called, so we don't need to check that\n expect(result.current.suggestions).toEqual(mockSuggestions);\n });\n\n it(\"should not generate suggestions when latest message is not from Tambo\", async () => {\n const mockGenerate = jest.fn();\n (useTamboClient as jest.Mock).mockReturnValue({\n beta: { threads: { suggestions: { generate: mockGenerate } } },\n });\n\n // Mock the thread to have a non-Tambo message\n (useTamboThread as jest.Mock).mockReturnValue({\n thread: {\n id: \"test-thread-id\",\n messages: [\n { id: \"test-message-id\", role: \"user\", content: \"Test message\" },\n ],\n },\n });\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n // Wait for the effect to run\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n\n expect(mockGenerate).not.toHaveBeenCalled();\n expect(result.current.suggestions).toEqual([]);\n });\n\n it(\"should accept a suggestion and update input value\", async () => {\n const mockSetValue = jest.fn();\n (useTamboThreadInput as jest.Mock).mockReturnValue({\n setValue: mockSetValue,\n });\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await result.current.accept({\n suggestion: mockSuggestions[0],\n shouldSubmit: false,\n });\n });\n\n expect(mockSetValue).toHaveBeenCalledWith(\"Test suggestion 1\");\n expect(result.current.selectedSuggestionId).toBe(\"suggestion-1\");\n });\n\n it(\"should accept a suggestion and submit it\", async () => {\n const mockSendThreadMessage = jest.fn();\n (useTambo as jest.Mock).mockReturnValue({\n sendThreadMessage: mockSendThreadMessage,\n });\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await result.current.accept({\n suggestion: mockSuggestions[0],\n shouldSubmit: true,\n });\n });\n\n expect(mockSendThreadMessage).toHaveBeenCalledWith(\"Test suggestion 1\", {\n threadId: \"test-thread-id\",\n });\n expect(result.current.selectedSuggestionId).toBe(\"suggestion-1\");\n });\n\n it(\"should throw error when accepting invalid suggestion\", async () => {\n const invalidSuggestion = {\n id: \"invalid-suggestion\",\n messageId: \"test-message-id\",\n title: \"Invalid Suggestion\",\n detailedSuggestion: \"\", // Empty suggestion should fail validation\n };\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await expect(\n result.current.accept({\n suggestion: invalidSuggestion,\n shouldSubmit: false,\n }),\n ).rejects.toThrow(\"Message cannot be empty\");\n });\n\n expect(result.current.selectedSuggestionId).toBeNull();\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"use-suggestions.test.js","sourceRoot":"","sources":["../../../src/hooks/__tests__/use-suggestions.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import type TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { QueryClient, UseQueryResult } from \"@tanstack/react-query\";\nimport { act, renderHook } from \"@testing-library/react\";\nimport { TamboThreadMessage } from \"../../model/generate-component-response\";\nimport {\n useTamboClient,\n useTamboQueryClient,\n} from \"../../providers/tambo-client-provider\";\nimport { TamboContextProps, useTambo } from \"../../providers/tambo-provider\";\nimport {\n TamboThreadContextProps,\n useTamboThread,\n} from \"../../providers/tambo-thread-provider\";\nimport { PartialTamboAI } from \"../../testing/types\";\nimport { useTamboMutation, useTamboQuery } from \"../react-query-hooks\";\nimport { useTamboSuggestions } from \"../use-suggestions\";\nimport { useTamboThreadInput, UseThreadInput } from \"../use-thread-input\";\n\n// Mock the required providers\njest.mock(\"../../providers/tambo-client-provider\", () => ({\n useTamboClient: jest.fn(),\n useTamboQueryClient: jest.fn(),\n}));\n\njest.mock(\"../../providers/tambo-provider\", () => ({ useTambo: jest.fn() }));\n\njest.mock(\"../../providers/tambo-thread-provider\", () => ({\n useTamboThread: jest.fn(),\n}));\n\njest.mock(\"../use-thread-input\", () => ({ useTamboThreadInput: jest.fn() }));\n\n// Mock the react-query-hooks\njest.mock(\"../react-query-hooks\", () => ({\n useTamboQuery: jest.fn(),\n useTamboMutation: jest.fn(),\n}));\n\ndescribe(\"useTamboSuggestions\", () => {\n const mockSuggestions: TamboAI.Beta.Threads.Suggestion[] = [\n {\n id: \"suggestion-1\",\n messageId: \"test-message-id\",\n title: \"Test Suggestion 1\",\n detailedSuggestion: \"Test suggestion 1\",\n },\n {\n id: \"suggestion-2\",\n messageId: \"test-message-id\",\n title: \"Test Suggestion 2\",\n detailedSuggestion: \"Test suggestion 2\",\n },\n ];\n\n beforeEach(() => {\n jest.mocked(useTamboQueryClient).mockReturnValue(new QueryClient());\n jest.mocked(useTamboMutation).mockImplementation(\n ({ mutationFn }) =>\n ({\n mutateAsync: mutationFn,\n isLoading: false,\n isError: false,\n error: null,\n }) as any,\n );\n // Setup default mock implementations\n jest.mocked(useTamboClient).mockReturnValue({\n beta: { threads: { suggestions: { generate: jest.fn() } } },\n } satisfies PartialTamboAI as any);\n jest.mocked(useTambo).mockReturnValue({\n sendThreadMessage: jest.fn(),\n } satisfies Partial<TamboContextProps> as any);\n jest.mocked(useTamboThread).mockReturnValue({\n thread: {\n id: \"test-thread-id\",\n messages: [\n {\n id: \"test-message-id\",\n role: \"hydra\",\n content: [{ type: \"text\", text: \"Test message\" }],\n },\n ],\n },\n } as TamboThreadContextProps);\n jest.mocked(useTamboThreadInput).mockReturnValue({\n setValue: jest.fn(),\n value: \"\",\n submit: jest.fn(),\n } satisfies Partial<UseThreadInput> as any);\n // Default query mock returns empty array\n jest.mocked(useTamboQuery).mockReturnValue({\n data: [],\n isLoading: false,\n isError: false,\n error: null,\n } satisfies Partial<UseQueryResult<unknown, unknown>> as any);\n });\n\n it(\"should initialize with empty suggestions and no selected suggestion\", () => {\n const { result } = renderHook(() => useTamboSuggestions());\n\n expect(result.current.suggestions).toEqual([]);\n expect(result.current.selectedSuggestionId).toBeNull();\n });\n\n it(\"should generate suggestions when latest message is from Tambo\", async () => {\n const mockGenerate = jest.fn().mockResolvedValue(mockSuggestions);\n jest.mocked(useTamboClient).mockReturnValue({\n beta: {\n threads: {\n suggestions: {\n generate: mockGenerate,\n list: jest.fn(),\n },\n },\n },\n } satisfies PartialTamboAI as any);\n jest.mocked(useTamboThread).mockReturnValue({\n thread: {\n id: \"test-thread-id\",\n messages: [\n {\n id: \"test-message-id\",\n role: \"assistant\",\n content: [{ type: \"text\", text: \"Test message\" }],\n } as TamboThreadMessage,\n ],\n },\n } as TamboThreadContextProps);\n\n // Mock the query result to return the mock suggestions\n jest.mocked(useTamboQuery).mockReturnValue({\n data: mockSuggestions,\n isLoading: false,\n isError: false,\n error: null,\n } as UseQueryResult<unknown, unknown>);\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n // Wait for the effect to run\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n\n // Since we're mocking useTamboQuery to return the suggestions directly,\n // the generate function won't be called, so we don't need to check that\n expect(result.current.suggestions).toEqual(mockSuggestions);\n });\n\n it(\"should not generate suggestions when latest message is not from Tambo\", async () => {\n const mockGenerate = jest.fn();\n jest.mocked(useTamboClient).mockReturnValue({\n beta: {\n threads: {\n suggestions: {\n generate: mockGenerate,\n list: jest.fn(),\n },\n },\n },\n } satisfies PartialTamboAI as any);\n // Mock the thread to have a non-Tambo message\n jest.mocked(useTamboThread).mockReturnValue({\n thread: {\n id: \"test-thread-id\",\n messages: [\n {\n id: \"test-message-id\",\n role: \"user\",\n content: [{ type: \"text\", text: \"Test message\" }],\n } as TamboThreadMessage,\n ],\n },\n } as TamboThreadContextProps);\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n // Wait for the effect to run\n await act(async () => {\n await new Promise((resolve) => setTimeout(resolve, 0));\n });\n\n expect(mockGenerate).not.toHaveBeenCalled();\n expect(result.current.suggestions).toEqual([]);\n });\n\n it(\"should accept a suggestion and update input value\", async () => {\n const mockSetValue = jest.fn();\n jest.mocked(useTamboThreadInput).mockReturnValue({\n setValue: mockSetValue,\n value: \"\",\n submit: jest.fn(),\n } satisfies Partial<UseThreadInput> as any);\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await result.current.accept({\n suggestion: mockSuggestions[0],\n shouldSubmit: false,\n });\n });\n\n expect(mockSetValue).toHaveBeenCalledWith(\"Test suggestion 1\");\n expect(result.current.selectedSuggestionId).toBe(\"suggestion-1\");\n });\n\n it(\"should accept a suggestion and submit it\", async () => {\n const mockSendThreadMessage = jest.fn();\n jest.mocked(useTambo).mockReturnValue({\n sendThreadMessage: mockSendThreadMessage,\n } satisfies Partial<TamboContextProps> as any);\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await result.current.accept({\n suggestion: mockSuggestions[0],\n shouldSubmit: true,\n });\n });\n\n expect(mockSendThreadMessage).toHaveBeenCalledWith(\"Test suggestion 1\", {\n threadId: \"test-thread-id\",\n });\n expect(result.current.selectedSuggestionId).toBe(\"suggestion-1\");\n });\n\n it(\"should throw error when accepting invalid suggestion\", async () => {\n const invalidSuggestion = {\n id: \"invalid-suggestion\",\n messageId: \"test-message-id\",\n title: \"Invalid Suggestion\",\n detailedSuggestion: \"\", // Empty suggestion should fail validation\n };\n\n const { result } = renderHook(() => useTamboSuggestions());\n\n await act(async () => {\n await expect(\n result.current.accept({\n suggestion: invalidSuggestion,\n shouldSubmit: false,\n }),\n ).rejects.toThrow(\"Message cannot be empty\");\n });\n\n expect(result.current.selectedSuggestionId).toBeNull();\n });\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tambo-threads.test.d.ts","sourceRoot":"","sources":["../../../src/hooks/__tests__/use-tambo-threads.test.tsx"],"names":[],"mappings":""}
|