@tambo-ai/react 0.62.0 → 0.64.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-voice.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/mcp-hooks.test.js +479 -16
- package/dist/mcp/__tests__/mcp-hooks.test.js.map +1 -1
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js +156 -0
- package/dist/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/dist/mcp/index.d.ts +2 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +3 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/mcp-hooks.d.ts +93 -3
- package/dist/mcp/mcp-hooks.d.ts.map +1 -1
- package/dist/mcp/mcp-hooks.js +111 -4
- package/dist/mcp/mcp-hooks.js.map +1 -1
- package/dist/mcp/tambo-mcp-provider.d.ts +16 -0
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +71 -7
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/providers/__tests__/tambo-context-attachment-provider.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-context-attachment-provider.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-context-attachment-provider.test.js +633 -0
- package/dist/providers/__tests__/tambo-context-attachment-provider.test.js.map +1 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +4 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/tambo-context-attachment-provider.d.ts +132 -0
- package/dist/providers/tambo-context-attachment-provider.d.ts.map +1 -0
- package/dist/providers/tambo-context-attachment-provider.js +201 -0
- package/dist/providers/tambo-context-attachment-provider.js.map +1 -0
- package/dist/providers/tambo-provider.d.ts +4 -2
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +9 -4
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-stubs.d.ts.map +1 -1
- package/dist/providers/tambo-stubs.js +6 -2
- package/dist/providers/tambo-stubs.js.map +1 -1
- package/esm/hooks/use-tambo-voice.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/mcp/__tests__/mcp-hooks.test.js +480 -17
- package/esm/mcp/__tests__/mcp-hooks.test.js.map +1 -1
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js +156 -0
- package/esm/mcp/__tests__/tambo-mcp-provider.test.js.map +1 -1
- package/esm/mcp/index.d.ts +2 -1
- package/esm/mcp/index.d.ts.map +1 -1
- package/esm/mcp/index.js +1 -1
- package/esm/mcp/index.js.map +1 -1
- package/esm/mcp/mcp-hooks.d.ts +93 -3
- package/esm/mcp/mcp-hooks.d.ts.map +1 -1
- package/esm/mcp/mcp-hooks.js +109 -4
- package/esm/mcp/mcp-hooks.js.map +1 -1
- package/esm/mcp/tambo-mcp-provider.d.ts +16 -0
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +71 -7
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/providers/__tests__/tambo-context-attachment-provider.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-context-attachment-provider.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-context-attachment-provider.test.js +628 -0
- package/esm/providers/__tests__/tambo-context-attachment-provider.test.js.map +1 -0
- package/esm/providers/index.d.ts +1 -0
- package/esm/providers/index.d.ts.map +1 -1
- package/esm/providers/index.js +1 -0
- package/esm/providers/index.js.map +1 -1
- package/esm/providers/tambo-context-attachment-provider.d.ts +132 -0
- package/esm/providers/tambo-context-attachment-provider.d.ts.map +1 -0
- package/esm/providers/tambo-context-attachment-provider.js +164 -0
- package/esm/providers/tambo-context-attachment-provider.js.map +1 -0
- package/esm/providers/tambo-provider.d.ts +4 -2
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +9 -4
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-stubs.d.ts.map +1 -1
- package/esm/providers/tambo-stubs.js +6 -2
- package/esm/providers/tambo-stubs.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tambo-voice.js","sourceRoot":"","sources":["../../src/hooks/use-tambo-voice.tsx"],"names":[],"mappings":";;AAgBA,sCAyEC;AAzFD,iCAAyD;AACzD,+DAA6D;AAC7D,8EAAoE;AACpE,2DAAuD;AAEvD;;;;;;;;;;GAUG;AACH,SAAgB,aAAa;IAC3B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,IAAA,gBAAQ,EAAgB,IAAI,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAA,sCAAc,GAAE,CAAC;IAChC,MAAM,EACJ,MAAM,EACN,cAAc,EAAE,mBAAmB,EACnC,aAAa,EAAE,kBAAkB,EACjC,YAAY,EACZ,KAAK,EAAE,gBAAgB,GACxB,GAAG,IAAA,4CAAqB,EAAC;QACxB,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,KAAK;QACZ,eAAe,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;KACxC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,KAAK,WAAW,CAAC;IAE3C,MAAM,qBAAqB,GAAG,IAAA,oCAAgB,EAI5C;QACA,UAAU,EAAE,KAAK,EAAE,OAAe,EAAE,EAAE;YACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,gBAAgB,EAAE;gBACnD,IAAI,EAAE,YAAY;aACnB,CAAC,CAAC;YAEH,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,SAAS,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"use-tambo-voice.js","sourceRoot":"","sources":["../../src/hooks/use-tambo-voice.tsx"],"names":[],"mappings":";;AAgBA,sCAyEC;AAzFD,iCAAyD;AACzD,+DAA6D;AAC7D,8EAAoE;AACpE,2DAAuD;AAEvD;;;;;;;;;;GAUG;AACH,SAAgB,aAAa;IAC3B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,IAAA,gBAAQ,EAAgB,IAAI,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAA,sCAAc,GAAE,CAAC;IAChC,MAAM,EACJ,MAAM,EACN,cAAc,EAAE,mBAAmB,EACnC,aAAa,EAAE,kBAAkB,EACjC,YAAY,EACZ,KAAK,EAAE,gBAAgB,GACxB,GAAG,IAAA,4CAAqB,EAAC;QACxB,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,KAAK;QACZ,eAAe,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;KACxC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,KAAK,WAAW,CAAC;IAE3C,MAAM,qBAAqB,GAAG,IAAA,oCAAgB,EAI5C;QACA,UAAU,EAAE,KAAK,EAAE,OAAe,EAAE,EAAE;YACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,gBAAgB,EAAE;gBACnD,IAAI,EAAE,YAAY;aACnB,CAAC,CAAC;YAEH,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,SAAS,EAAE,CAAC,aAAqB,EAAE,EAAE;YACnC,aAAa,CAAC,aAAa,CAAC,CAAC;QAC/B,CAAC;KACF,CAAC,CAAC;IAEH,oEAAoE;IACpE,MAAM,gBAAgB,GACpB,MAAM,KAAK,SAAS;QACpB,YAAY;QACZ,CAAC,qBAAqB,CAAC,SAAS;QAChC,CAAC,qBAAqB,CAAC,SAAS,CAAC;IAEnC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,gBAAgB,EAAE,CAAC;YACrB,qBAAqB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,EAAE,CAAC,gBAAgB,EAAE,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAE5D,MAAM,cAAc,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QACtC,IAAI,WAAW;YAAE,OAAO;QAExB,0CAA0C;QAC1C,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,qBAAqB,CAAC,KAAK,EAAE,CAAC,CAAC,oCAAoC;QACnE,mBAAmB,EAAE,CAAC;IACxB,CAAC,EAAE,CAAC,WAAW,EAAE,mBAAmB,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAE9D,MAAM,aAAa,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QACrC,IAAI,WAAW,EAAE,CAAC;YAChB,kBAAkB,EAAE,CAAC;QACvB,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAEtC,OAAO;QACL,cAAc;QACd,aAAa;QACb,WAAW;QACX,gBAAgB,EAAE,gBAAgB,IAAI,IAAI;QAC1C,cAAc,EAAE,qBAAqB,CAAC,SAAS;QAC/C,UAAU;QACV,kBAAkB,EAAE,qBAAqB,CAAC,KAAK,EAAE,OAAO,IAAI,IAAI;KACjE,CAAC;AACJ,CAAC","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport { useReactMediaRecorder } from \"react-media-recorder\";\nimport { useTamboClient } from \"../providers/tambo-client-provider\";\nimport { useTamboMutation } from \"./react-query-hooks\";\n\n/**\n * Exposes functionality to record speech and transcribe it using the Tambo API.\n * @returns An object with:\n * - startRecording: A function to start recording audio and reset the current transcript.\n * - stopRecording: A function to stop recording audio and automatically kick off transcription.\n * - isRecording: A boolean indicating if the user is recording audio.\n * - isTranscribing: A boolean indicating if the audio is being transcribed.\n * - transcript: The transcript of the recorded audio.\n * - transcriptionError: An error message if the transcription fails.\n * - mediaAccessError: An error message if microphone access fails.\n */\nexport function useTamboVoice() {\n const [transcript, setTranscript] = useState<string | null>(null);\n const client = useTamboClient();\n const {\n status,\n startRecording: startMediaRecording,\n stopRecording: stopMediaRecording,\n mediaBlobUrl,\n error: mediaAccessError,\n } = useReactMediaRecorder({\n audio: true,\n video: false,\n blobPropertyBag: { type: \"audio/webm\" },\n });\n\n const isRecording = status === \"recording\";\n\n const transcriptionMutation = useTamboMutation<\n string,\n Error,\n string // blobUrl parameter\n >({\n mutationFn: async (blobUrl: string) => {\n const response = await fetch(blobUrl);\n const audioBlob = await response.blob();\n const file = new File([audioBlob], \"recording.webm\", {\n type: \"audio/webm\",\n });\n\n return await client.beta.audio.transcribe({ file });\n },\n onSuccess: (transcription: string) => {\n setTranscript(transcription);\n },\n });\n\n // Trigger transcription when recording stops and we have a blob URL\n const shouldTranscribe =\n status === \"stopped\" &&\n mediaBlobUrl &&\n !transcriptionMutation.isPending &&\n !transcriptionMutation.isSuccess;\n\n useEffect(() => {\n if (shouldTranscribe) {\n transcriptionMutation.mutate(mediaBlobUrl);\n }\n }, [shouldTranscribe, mediaBlobUrl, transcriptionMutation]);\n\n const startRecording = useCallback(() => {\n if (isRecording) return;\n\n // Reset state when starting new recording\n setTranscript(null);\n transcriptionMutation.reset(); // Clear any previous mutation state\n startMediaRecording();\n }, [isRecording, startMediaRecording, transcriptionMutation]);\n\n const stopRecording = useCallback(() => {\n if (isRecording) {\n stopMediaRecording();\n }\n }, [isRecording, stopMediaRecording]);\n\n return {\n startRecording,\n stopRecording,\n isRecording,\n mediaAccessError: mediaAccessError ?? null,\n isTranscribing: transcriptionMutation.isPending,\n transcript,\n transcriptionError: transcriptionMutation.error?.message ?? null,\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export { useTamboStreamingProps } from "./hooks/use-streaming-props";
|
|
|
6
6
|
export * from "./hooks/use-suggestions";
|
|
7
7
|
export { useTamboStreamStatus, type PropStatus, type StreamStatus, } from "./hooks/use-tambo-stream-status";
|
|
8
8
|
export { useTamboVoice } from "./hooks/use-tambo-voice";
|
|
9
|
-
export { TamboClientProvider, TamboComponentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadInputProvider, TamboThreadProvider, useIsTamboTokenUpdating, useTambo, useTamboClient, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, useTamboThreadInput, type TamboComponent, type TamboContextHelpersContextProps, type TamboContextHelpersProviderProps, type TamboRegistryContext, type TamboStubProviderProps, type TamboThreadInputContextProps, type TamboThreadProviderProps, } from "./providers";
|
|
9
|
+
export { TamboClientProvider, TamboComponentProvider, TamboContextAttachmentProvider, TamboContextHelpersProvider, TamboPropStreamProvider, TamboProvider, TamboStubProvider, TamboThreadInputProvider, TamboThreadProvider, useIsTamboTokenUpdating, useTambo, useTamboClient, useTamboContextAttachment, useTamboContextHelpers, useTamboGenerationStage, useTamboStream, useTamboThread, useTamboThreadInput, type ContextAttachment, type ContextAttachmentState, type ContextHelperData, type TamboComponent, type TamboContextAttachmentProviderProps, type TamboContextHelpersContextProps, type TamboContextHelpersProviderProps, type TamboRegistryContext, type TamboStubProviderProps, type TamboThreadInputContextProps, type TamboThreadProviderProps, } from "./providers";
|
|
10
10
|
export type { APIError, RateLimitError, TamboAIError, } from "@tambo-ai/typescript-sdk";
|
|
11
11
|
export type { Suggestion, SuggestionGenerateParams, SuggestionGenerateResponse, SuggestionListResponse, } from "@tambo-ai/typescript-sdk/resources/beta/threads/suggestions";
|
|
12
12
|
export { useTamboThreadList } from "./hooks/use-tambo-threads";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,GAC9B,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAEnF,YAAY,EACV,0BAA0B,IAAI,qBAAqB,EACnD,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,IAAI,gBAAgB,EACzC,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wKAAwK;AAExK,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,cAAc,yBAAyB,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC3B,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,mCAAmC,EACxC,KAAK,+BAA+B,EACpC,KAAK,gCAAgC,EACrC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,GAC9B,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,UAAU,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,SAAS,GACf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,GACxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAEnF,YAAY,EACV,0BAA0B,IAAI,qBAAqB,EACnD,wBAAwB,GACzB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,IAAI,gBAAgB,EACzC,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,+BAA+B,EAC/B,oBAAoB,GACrB,MAAM,yCAAyC,CAAC;AAGjD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.currentTimeContextHelper = exports.currentPageContextHelper = exports.useTamboInteractable = exports.useCurrentInteractablesSnapshot = exports.withInteractable = exports.GenerationStage = exports.useTamboThreadList = exports.useTamboThreadInput = exports.useTamboThread = exports.useTamboStream = exports.useTamboGenerationStage = exports.useTamboContextHelpers = exports.useTamboClient = exports.useTambo = exports.useIsTamboTokenUpdating = exports.TamboThreadProvider = exports.TamboThreadInputProvider = exports.TamboStubProvider = exports.TamboProvider = exports.TamboPropStreamProvider = exports.TamboContextHelpersProvider = exports.TamboComponentProvider = exports.TamboClientProvider = exports.useTamboVoice = exports.useTamboStreamStatus = exports.useTamboStreamingProps = exports.useMessageImages = exports.useTamboCurrentMessage = exports.TamboMessageProvider = exports.useTamboComponentState = void 0;
|
|
18
|
+
exports.currentTimeContextHelper = exports.currentPageContextHelper = exports.useTamboInteractable = exports.useCurrentInteractablesSnapshot = exports.withInteractable = exports.GenerationStage = exports.useTamboThreadList = exports.useTamboThreadInput = exports.useTamboThread = exports.useTamboStream = exports.useTamboGenerationStage = exports.useTamboContextHelpers = exports.useTamboContextAttachment = exports.useTamboClient = exports.useTambo = exports.useIsTamboTokenUpdating = exports.TamboThreadProvider = exports.TamboThreadInputProvider = exports.TamboStubProvider = exports.TamboProvider = exports.TamboPropStreamProvider = exports.TamboContextHelpersProvider = exports.TamboContextAttachmentProvider = exports.TamboComponentProvider = exports.TamboClientProvider = exports.useTamboVoice = exports.useTamboStreamStatus = exports.useTamboStreamingProps = exports.useMessageImages = exports.useTamboCurrentMessage = exports.TamboMessageProvider = exports.useTamboComponentState = void 0;
|
|
19
19
|
var use_component_state_1 = require("./hooks/use-component-state");
|
|
20
20
|
Object.defineProperty(exports, "useTamboComponentState", { enumerable: true, get: function () { return use_component_state_1.useTamboComponentState; } });
|
|
21
21
|
var use_current_message_1 = require("./hooks/use-current-message");
|
|
@@ -34,6 +34,7 @@ Object.defineProperty(exports, "useTamboVoice", { enumerable: true, get: functio
|
|
|
34
34
|
var providers_1 = require("./providers");
|
|
35
35
|
Object.defineProperty(exports, "TamboClientProvider", { enumerable: true, get: function () { return providers_1.TamboClientProvider; } });
|
|
36
36
|
Object.defineProperty(exports, "TamboComponentProvider", { enumerable: true, get: function () { return providers_1.TamboComponentProvider; } });
|
|
37
|
+
Object.defineProperty(exports, "TamboContextAttachmentProvider", { enumerable: true, get: function () { return providers_1.TamboContextAttachmentProvider; } });
|
|
37
38
|
Object.defineProperty(exports, "TamboContextHelpersProvider", { enumerable: true, get: function () { return providers_1.TamboContextHelpersProvider; } });
|
|
38
39
|
Object.defineProperty(exports, "TamboPropStreamProvider", { enumerable: true, get: function () { return providers_1.TamboPropStreamProvider; } });
|
|
39
40
|
Object.defineProperty(exports, "TamboProvider", { enumerable: true, get: function () { return providers_1.TamboProvider; } });
|
|
@@ -43,6 +44,7 @@ Object.defineProperty(exports, "TamboThreadProvider", { enumerable: true, get: f
|
|
|
43
44
|
Object.defineProperty(exports, "useIsTamboTokenUpdating", { enumerable: true, get: function () { return providers_1.useIsTamboTokenUpdating; } });
|
|
44
45
|
Object.defineProperty(exports, "useTambo", { enumerable: true, get: function () { return providers_1.useTambo; } });
|
|
45
46
|
Object.defineProperty(exports, "useTamboClient", { enumerable: true, get: function () { return providers_1.useTamboClient; } });
|
|
47
|
+
Object.defineProperty(exports, "useTamboContextAttachment", { enumerable: true, get: function () { return providers_1.useTamboContextAttachment; } });
|
|
46
48
|
Object.defineProperty(exports, "useTamboContextHelpers", { enumerable: true, get: function () { return providers_1.useTamboContextHelpers; } });
|
|
47
49
|
Object.defineProperty(exports, "useTamboGenerationStage", { enumerable: true, get: function () { return providers_1.useTamboGenerationStage; } });
|
|
48
50
|
Object.defineProperty(exports, "useTamboStream", { enumerable: true, get: function () { return providers_1.useTamboStream; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,wKAAwK;;;;;;;;;;;;;;;;;AAExK,mEAAqE;AAA5D,6HAAA,sBAAsB,OAAA;AAC/B,mEAGqC;AAFnC,2HAAA,oBAAoB,OAAA;AACpB,6HAAA,sBAAsB,OAAA;AAExB,iEAAgF;AAAvE,sHAAA,gBAAgB,OAAA;AACzB,mEAAqE;AAA5D,6HAAA,sBAAsB,OAAA;AAC/B,0DAAwC;AACxC,2EAIyC;AAHvC,+HAAA,oBAAoB,OAAA;AAItB,2DAAwD;AAA/C,gHAAA,aAAa,OAAA;AAEtB,gCAAgC;AAChC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,wKAAwK;;;;;;;;;;;;;;;;;AAExK,mEAAqE;AAA5D,6HAAA,sBAAsB,OAAA;AAC/B,mEAGqC;AAFnC,2HAAA,oBAAoB,OAAA;AACpB,6HAAA,sBAAsB,OAAA;AAExB,iEAAgF;AAAvE,sHAAA,gBAAgB,OAAA;AACzB,mEAAqE;AAA5D,6HAAA,sBAAsB,OAAA;AAC/B,0DAAwC;AACxC,2EAIyC;AAHvC,+HAAA,oBAAoB,OAAA;AAItB,2DAAwD;AAA/C,gHAAA,aAAa,OAAA;AAEtB,gCAAgC;AAChC,yCA8BqB;AA7BnB,gHAAA,mBAAmB,OAAA;AACnB,mHAAA,sBAAsB,OAAA;AACtB,2HAAA,8BAA8B,OAAA;AAC9B,wHAAA,2BAA2B,OAAA;AAC3B,oHAAA,uBAAuB,OAAA;AACvB,0GAAA,aAAa,OAAA;AACb,8GAAA,iBAAiB,OAAA;AACjB,qHAAA,wBAAwB,OAAA;AACxB,gHAAA,mBAAmB,OAAA;AACnB,oHAAA,uBAAuB,OAAA;AACvB,qGAAA,QAAQ,OAAA;AACR,2GAAA,cAAc,OAAA;AACd,sHAAA,yBAAyB,OAAA;AACzB,mHAAA,sBAAsB,OAAA;AACtB,oHAAA,uBAAuB,OAAA;AACvB,2GAAA,cAAc,OAAA;AACd,2GAAA,cAAc,OAAA;AACd,gHAAA,mBAAmB,OAAA;AA0BrB,+DAA+D;AAAtD,uHAAA,kBAAkB,OAAA;AAQ3B,mFAG6C;AAF3C,8HAAA,eAAe,OAAA;AAUjB,mFAIiD;AAH/C,2HAAA,qBAAqB,OAAoB;AAI3C,uFAGiD;AAF/C,8IAAA,+BAA+B,OAAA;AAC/B,mIAAA,oBAAoB,OAAA;AAGtB,0BAA0B;AAC1B,qDAG2B;AAFzB,2HAAA,wBAAwB,OAAA;AACxB,2HAAA,wBAAwB,OAAA;AAQ1B,yEAAyE;AACzE,8BAA8B","sourcesContent":["/** Exports for the library. Only publically available exports are re-exported here. Anything not exported here is not supported and may change or break at any time. */\n\nexport { useTamboComponentState } from \"./hooks/use-component-state\";\nexport {\n TamboMessageProvider,\n useTamboCurrentMessage,\n} from \"./hooks/use-current-message\";\nexport { useMessageImages, type StagedImage } from \"./hooks/use-message-images\";\nexport { useTamboStreamingProps } from \"./hooks/use-streaming-props\";\nexport * from \"./hooks/use-suggestions\";\nexport {\n useTamboStreamStatus,\n type PropStatus,\n type StreamStatus,\n} from \"./hooks/use-tambo-stream-status\";\nexport { useTamboVoice } from \"./hooks/use-tambo-voice\";\n\n// Re-export provider components\nexport {\n TamboClientProvider,\n TamboComponentProvider,\n TamboContextAttachmentProvider,\n TamboContextHelpersProvider,\n TamboPropStreamProvider,\n TamboProvider,\n TamboStubProvider,\n TamboThreadInputProvider,\n TamboThreadProvider,\n useIsTamboTokenUpdating,\n useTambo,\n useTamboClient,\n useTamboContextAttachment,\n useTamboContextHelpers,\n useTamboGenerationStage,\n useTamboStream,\n useTamboThread,\n useTamboThreadInput,\n type ContextAttachment,\n type ContextAttachmentState,\n type ContextHelperData,\n type TamboComponent,\n type TamboContextAttachmentProviderProps,\n type TamboContextHelpersContextProps,\n type TamboContextHelpersProviderProps,\n type TamboRegistryContext,\n type TamboStubProviderProps,\n type TamboThreadInputContextProps,\n type TamboThreadProviderProps,\n} from \"./providers\";\n\n// Re-export types from Tambo Node SDK\nexport type {\n APIError,\n RateLimitError,\n TamboAIError,\n} from \"@tambo-ai/typescript-sdk\";\nexport type {\n Suggestion,\n SuggestionGenerateParams,\n SuggestionGenerateResponse,\n SuggestionListResponse,\n} from \"@tambo-ai/typescript-sdk/resources/beta/threads/suggestions\";\nexport { useTamboThreadList } from \"./hooks/use-tambo-threads\";\nexport {\n type ComponentContextToolMetadata,\n type ComponentRegistry,\n type ParameterSpec,\n type RegisteredComponent,\n type TamboTool,\n} from \"./model/component-metadata\";\nexport {\n GenerationStage,\n type TamboThreadMessage,\n} from \"./model/generate-component-response\";\nexport { type TamboThread } from \"./model/tambo-thread\";\nexport { type InitialTamboThreadMessage } from \"./providers/tambo-thread-provider\";\n\nexport type {\n TamboInteractableComponent as InteractableComponent,\n TamboInteractableContext,\n} from \"./model/tambo-interactable\";\nexport {\n withTamboInteractable as withInteractable,\n type InteractableConfig,\n type WithTamboInteractableProps,\n} from \"./providers/hoc/with-tambo-interactable\";\nexport {\n useCurrentInteractablesSnapshot,\n useTamboInteractable,\n} from \"./providers/tambo-interactable-provider\";\n\n// Context helpers exports\nexport {\n currentPageContextHelper,\n currentTimeContextHelper,\n} from \"./context-helpers\";\nexport type {\n AdditionalContext,\n ContextHelperFn,\n ContextHelpers,\n} from \"./context-helpers\";\n\n// Note MCP exports like TamboMcpProvider are available separately in the\n// @tambo-ai/react/mcp package\n"]}
|
|
@@ -137,16 +137,16 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
137
137
|
await (0, react_1.waitFor)(() => {
|
|
138
138
|
expect(capturedPrompts.length).toBe(4);
|
|
139
139
|
});
|
|
140
|
-
// Verify all prompts are present
|
|
140
|
+
// Verify all prompts are present (with prefixes since we have 2 servers)
|
|
141
141
|
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
142
|
-
expect(promptNames).toContain("prompt-a1");
|
|
143
|
-
expect(promptNames).toContain("prompt-a2");
|
|
144
|
-
expect(promptNames).toContain("prompt-b1");
|
|
145
|
-
expect(promptNames).toContain("prompt-b2");
|
|
142
|
+
expect(promptNames).toContain("server-a:prompt-a1");
|
|
143
|
+
expect(promptNames).toContain("server-a:prompt-a2");
|
|
144
|
+
expect(promptNames).toContain("server-b:prompt-b1");
|
|
145
|
+
expect(promptNames).toContain("server-b:prompt-b2");
|
|
146
146
|
// Verify each prompt has the correct server info
|
|
147
|
-
const promptA1 = capturedPrompts.find((p) => p.prompt.name === "prompt-a1");
|
|
147
|
+
const promptA1 = capturedPrompts.find((p) => p.prompt.name === "server-a:prompt-a1");
|
|
148
148
|
expect(promptA1?.server.url).toBe("https://server-a.example");
|
|
149
|
-
const promptB1 = capturedPrompts.find((p) => p.prompt.name === "prompt-b1");
|
|
149
|
+
const promptB1 = capturedPrompts.find((p) => p.prompt.name === "server-b:prompt-b1");
|
|
150
150
|
expect(promptB1?.server.url).toBe("https://server-b.example");
|
|
151
151
|
});
|
|
152
152
|
it("should remove prompts when a server is removed", async () => {
|
|
@@ -223,10 +223,10 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
223
223
|
expect(capturedPrompts.length).toBe(4);
|
|
224
224
|
});
|
|
225
225
|
const initialPromptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
226
|
-
expect(initialPromptNames).toContain("prompt-a1");
|
|
227
|
-
expect(initialPromptNames).toContain("prompt-a2");
|
|
228
|
-
expect(initialPromptNames).toContain("prompt-b1");
|
|
229
|
-
expect(initialPromptNames).toContain("prompt-b2");
|
|
226
|
+
expect(initialPromptNames).toContain("server-a:prompt-a1");
|
|
227
|
+
expect(initialPromptNames).toContain("server-a:prompt-a2");
|
|
228
|
+
expect(initialPromptNames).toContain("server-b:prompt-b1");
|
|
229
|
+
expect(initialPromptNames).toContain("server-b:prompt-b2");
|
|
230
230
|
// Remove server B
|
|
231
231
|
rerender(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
232
232
|
client: { baseURL: "https://api.tambo.co" },
|
|
@@ -243,6 +243,7 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
243
243
|
] },
|
|
244
244
|
react_2.default.createElement(Capture, null))))));
|
|
245
245
|
// Wait for prompts to be updated (server B prompts should disappear)
|
|
246
|
+
// When only 1 server remains, prompts should NOT be prefixed
|
|
246
247
|
await (0, react_1.waitFor)(() => {
|
|
247
248
|
expect(capturedPrompts.length).toBe(2);
|
|
248
249
|
});
|
|
@@ -251,6 +252,7 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
251
252
|
expect(updatedPromptNames).toContain("prompt-a2");
|
|
252
253
|
expect(updatedPromptNames).not.toContain("prompt-b1");
|
|
253
254
|
expect(updatedPromptNames).not.toContain("prompt-b2");
|
|
255
|
+
expect(updatedPromptNames).not.toContain("server-a:prompt-a1"); // No prefix when only 1 server
|
|
254
256
|
// Verify server B's client was closed
|
|
255
257
|
expect(clientB.close).toHaveBeenCalled();
|
|
256
258
|
});
|
|
@@ -405,10 +407,10 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
405
407
|
expect(capturedPrompts.length).toBe(1);
|
|
406
408
|
expect(mcpServersCount).toBe(2); // Both servers should be in the list
|
|
407
409
|
});
|
|
408
|
-
// Verify only server A's prompts are present
|
|
410
|
+
// Verify only server A's prompts are present (with prefix since 2 servers configured)
|
|
409
411
|
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
410
|
-
expect(promptNames).toContain("prompt-a");
|
|
411
|
-
expect(promptNames).not.toContain("prompt-b");
|
|
412
|
+
expect(promptNames).toContain("server-a:prompt-a");
|
|
413
|
+
expect(promptNames).not.toContain("server-b:prompt-b");
|
|
412
414
|
});
|
|
413
415
|
it("should add prompts when a new server is added", async () => {
|
|
414
416
|
const serverAPrompts = {
|
|
@@ -493,12 +495,473 @@ describe("useTamboMcpPromptList - individual server caching", () => {
|
|
|
493
495
|
] },
|
|
494
496
|
react_2.default.createElement(Capture, null))))));
|
|
495
497
|
// Wait for server B prompts to be added
|
|
498
|
+
// Now with 2 servers, prompts should be prefixed
|
|
496
499
|
await (0, react_1.waitFor)(() => {
|
|
497
500
|
expect(capturedPrompts.length).toBe(2);
|
|
498
501
|
});
|
|
499
502
|
const promptNames = capturedPrompts.map((p) => p.prompt.name);
|
|
500
|
-
expect(promptNames).toContain("prompt-a");
|
|
501
|
-
expect(promptNames).toContain("prompt-b");
|
|
503
|
+
expect(promptNames).toContain("server-a:prompt-a");
|
|
504
|
+
expect(promptNames).toContain("server-b:prompt-b");
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
describe("useTamboMcpResourceList - resource management", () => {
|
|
508
|
+
let queryClient;
|
|
509
|
+
beforeEach(() => {
|
|
510
|
+
createImpl = jest.fn();
|
|
511
|
+
queryClient = new react_query_1.QueryClient({
|
|
512
|
+
defaultOptions: {
|
|
513
|
+
queries: {
|
|
514
|
+
retry: false,
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
afterEach(() => {
|
|
520
|
+
queryClient.clear();
|
|
521
|
+
});
|
|
522
|
+
it("should fetch and combine resources from multiple servers", async () => {
|
|
523
|
+
// Mock two servers with different resources
|
|
524
|
+
const serverAResources = {
|
|
525
|
+
resources: [
|
|
526
|
+
{
|
|
527
|
+
uri: "file:///home/user/doc1.txt",
|
|
528
|
+
name: "Document 1",
|
|
529
|
+
mimeType: "text/plain",
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
uri: "file:///home/user/doc2.txt",
|
|
533
|
+
name: "Document 2",
|
|
534
|
+
mimeType: "text/plain",
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
};
|
|
538
|
+
const serverBResources = {
|
|
539
|
+
resources: [
|
|
540
|
+
{
|
|
541
|
+
uri: "file:///workspace/code.js",
|
|
542
|
+
name: "Code File",
|
|
543
|
+
mimeType: "text/javascript",
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
uri: "file:///workspace/README.md",
|
|
547
|
+
name: "Readme",
|
|
548
|
+
mimeType: "text/markdown",
|
|
549
|
+
},
|
|
550
|
+
],
|
|
551
|
+
};
|
|
552
|
+
const mockClientA = {
|
|
553
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
554
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
555
|
+
listResources: jest.fn().mockResolvedValue(serverAResources),
|
|
556
|
+
close: jest.fn(),
|
|
557
|
+
};
|
|
558
|
+
const mockClientB = {
|
|
559
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
560
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
561
|
+
listResources: jest.fn().mockResolvedValue(serverBResources),
|
|
562
|
+
close: jest.fn(),
|
|
563
|
+
};
|
|
564
|
+
const clientA = {
|
|
565
|
+
client: mockClientA,
|
|
566
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
567
|
+
close: jest.fn(),
|
|
568
|
+
};
|
|
569
|
+
const clientB = {
|
|
570
|
+
client: mockClientB,
|
|
571
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
572
|
+
close: jest.fn(),
|
|
573
|
+
};
|
|
574
|
+
createImpl.mockImplementation(async (url) => {
|
|
575
|
+
if (url === "https://server-a.example")
|
|
576
|
+
return clientA;
|
|
577
|
+
if (url === "https://server-b.example")
|
|
578
|
+
return clientB;
|
|
579
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
580
|
+
});
|
|
581
|
+
let capturedResources = [];
|
|
582
|
+
const Capture = () => {
|
|
583
|
+
const { data: resources } = (0, mcp_hooks_1.useTamboMcpResourceList)();
|
|
584
|
+
(0, react_2.useEffect)(() => {
|
|
585
|
+
if (resources) {
|
|
586
|
+
capturedResources = resources;
|
|
587
|
+
}
|
|
588
|
+
}, [resources]);
|
|
589
|
+
return null;
|
|
590
|
+
};
|
|
591
|
+
(0, react_1.render)(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
592
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
593
|
+
queryClient,
|
|
594
|
+
isUpdatingToken: false,
|
|
595
|
+
} },
|
|
596
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
597
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
598
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
599
|
+
{
|
|
600
|
+
url: "https://server-a.example",
|
|
601
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
url: "https://server-b.example",
|
|
605
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
606
|
+
},
|
|
607
|
+
] },
|
|
608
|
+
react_2.default.createElement(Capture, null))))));
|
|
609
|
+
// Wait for all resources to be loaded
|
|
610
|
+
await (0, react_1.waitFor)(() => {
|
|
611
|
+
expect(capturedResources.length).toBe(4);
|
|
612
|
+
});
|
|
613
|
+
// Verify all resources are present (with prefixes since we have 2 servers)
|
|
614
|
+
const resourceUris = capturedResources.map((r) => r.resource.uri);
|
|
615
|
+
expect(resourceUris).toContain("server-a:file:///home/user/doc1.txt");
|
|
616
|
+
expect(resourceUris).toContain("server-a:file:///home/user/doc2.txt");
|
|
617
|
+
expect(resourceUris).toContain("server-b:file:///workspace/code.js");
|
|
618
|
+
expect(resourceUris).toContain("server-b:file:///workspace/README.md");
|
|
619
|
+
// Verify each resource has the correct server info
|
|
620
|
+
const resource1 = capturedResources.find((r) => r.resource.uri === "server-a:file:///home/user/doc1.txt");
|
|
621
|
+
expect(resource1?.server.url).toBe("https://server-a.example");
|
|
622
|
+
const resource2 = capturedResources.find((r) => r.resource.uri === "server-b:file:///workspace/code.js");
|
|
623
|
+
expect(resource2?.server.url).toBe("https://server-b.example");
|
|
624
|
+
});
|
|
625
|
+
it("should not prefix resources when only one server exists", async () => {
|
|
626
|
+
const serverAResources = {
|
|
627
|
+
resources: [
|
|
628
|
+
{
|
|
629
|
+
uri: "file:///home/user/doc.txt",
|
|
630
|
+
name: "Document",
|
|
631
|
+
mimeType: "text/plain",
|
|
632
|
+
},
|
|
633
|
+
],
|
|
634
|
+
};
|
|
635
|
+
const mockClientA = {
|
|
636
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
637
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
638
|
+
listResources: jest.fn().mockResolvedValue(serverAResources),
|
|
639
|
+
close: jest.fn(),
|
|
640
|
+
};
|
|
641
|
+
const clientA = {
|
|
642
|
+
client: mockClientA,
|
|
643
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
644
|
+
close: jest.fn(),
|
|
645
|
+
};
|
|
646
|
+
createImpl.mockImplementation(async () => clientA);
|
|
647
|
+
let capturedResources = [];
|
|
648
|
+
const Capture = () => {
|
|
649
|
+
const { data: resources } = (0, mcp_hooks_1.useTamboMcpResourceList)();
|
|
650
|
+
(0, react_2.useEffect)(() => {
|
|
651
|
+
if (resources) {
|
|
652
|
+
capturedResources = resources;
|
|
653
|
+
}
|
|
654
|
+
}, [resources]);
|
|
655
|
+
return null;
|
|
656
|
+
};
|
|
657
|
+
(0, react_1.render)(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
658
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
659
|
+
queryClient,
|
|
660
|
+
isUpdatingToken: false,
|
|
661
|
+
} },
|
|
662
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
663
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
664
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
665
|
+
{
|
|
666
|
+
url: "https://server-a.example",
|
|
667
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
668
|
+
},
|
|
669
|
+
] },
|
|
670
|
+
react_2.default.createElement(Capture, null))))));
|
|
671
|
+
await (0, react_1.waitFor)(() => {
|
|
672
|
+
expect(capturedResources.length).toBe(1);
|
|
673
|
+
});
|
|
674
|
+
// No prefix when only 1 server
|
|
675
|
+
expect(capturedResources[0].resource.uri).toBe("file:///home/user/doc.txt");
|
|
676
|
+
});
|
|
677
|
+
it("should remove resource prefixes when a server is removed", async () => {
|
|
678
|
+
const serverAResources = {
|
|
679
|
+
resources: [
|
|
680
|
+
{
|
|
681
|
+
uri: "file:///home/user/doc1.txt",
|
|
682
|
+
name: "Document 1",
|
|
683
|
+
mimeType: "text/plain",
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
uri: "file:///home/user/doc2.txt",
|
|
687
|
+
name: "Document 2",
|
|
688
|
+
mimeType: "text/plain",
|
|
689
|
+
},
|
|
690
|
+
],
|
|
691
|
+
};
|
|
692
|
+
const serverBResources = {
|
|
693
|
+
resources: [
|
|
694
|
+
{
|
|
695
|
+
uri: "file:///workspace/code.js",
|
|
696
|
+
name: "Code File",
|
|
697
|
+
mimeType: "text/javascript",
|
|
698
|
+
},
|
|
699
|
+
],
|
|
700
|
+
};
|
|
701
|
+
const mockClientA = {
|
|
702
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
703
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
704
|
+
listResources: jest.fn().mockResolvedValue(serverAResources),
|
|
705
|
+
close: jest.fn(),
|
|
706
|
+
};
|
|
707
|
+
const mockClientB = {
|
|
708
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
709
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
710
|
+
listResources: jest.fn().mockResolvedValue(serverBResources),
|
|
711
|
+
close: jest.fn(),
|
|
712
|
+
};
|
|
713
|
+
const clientA = {
|
|
714
|
+
client: mockClientA,
|
|
715
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
716
|
+
close: jest.fn(),
|
|
717
|
+
};
|
|
718
|
+
const clientB = {
|
|
719
|
+
client: mockClientB,
|
|
720
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
721
|
+
close: jest.fn(),
|
|
722
|
+
};
|
|
723
|
+
createImpl.mockImplementation(async (url) => {
|
|
724
|
+
if (url === "https://server-a.example")
|
|
725
|
+
return clientA;
|
|
726
|
+
if (url === "https://server-b.example")
|
|
727
|
+
return clientB;
|
|
728
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
729
|
+
});
|
|
730
|
+
let capturedResources = [];
|
|
731
|
+
const Capture = () => {
|
|
732
|
+
const { data: resources } = (0, mcp_hooks_1.useTamboMcpResourceList)();
|
|
733
|
+
(0, react_2.useEffect)(() => {
|
|
734
|
+
if (resources) {
|
|
735
|
+
capturedResources = resources;
|
|
736
|
+
}
|
|
737
|
+
}, [resources]);
|
|
738
|
+
return null;
|
|
739
|
+
};
|
|
740
|
+
const { rerender } = (0, react_1.render)(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
741
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
742
|
+
queryClient,
|
|
743
|
+
isUpdatingToken: false,
|
|
744
|
+
} },
|
|
745
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
746
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
747
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
748
|
+
{
|
|
749
|
+
url: "https://server-a.example",
|
|
750
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
url: "https://server-b.example",
|
|
754
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
755
|
+
},
|
|
756
|
+
] },
|
|
757
|
+
react_2.default.createElement(Capture, null))))));
|
|
758
|
+
// Wait for all resources to be loaded (prefixed)
|
|
759
|
+
await (0, react_1.waitFor)(() => {
|
|
760
|
+
expect(capturedResources.length).toBe(3);
|
|
761
|
+
});
|
|
762
|
+
const initialUris = capturedResources.map((r) => r.resource.uri);
|
|
763
|
+
expect(initialUris).toContain("server-a:file:///home/user/doc1.txt");
|
|
764
|
+
expect(initialUris).toContain("server-b:file:///workspace/code.js");
|
|
765
|
+
// Now remove server B
|
|
766
|
+
rerender(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
767
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
768
|
+
queryClient,
|
|
769
|
+
isUpdatingToken: false,
|
|
770
|
+
} },
|
|
771
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
772
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
773
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
774
|
+
{
|
|
775
|
+
url: "https://server-a.example",
|
|
776
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
777
|
+
},
|
|
778
|
+
] },
|
|
779
|
+
react_2.default.createElement(Capture, null))))));
|
|
780
|
+
// Wait for server B resources to be removed and prefixes stripped
|
|
781
|
+
await (0, react_1.waitFor)(() => {
|
|
782
|
+
expect(capturedResources.length).toBe(2);
|
|
783
|
+
});
|
|
784
|
+
const updatedUris = capturedResources.map((r) => r.resource.uri);
|
|
785
|
+
expect(updatedUris).toContain("file:///home/user/doc1.txt"); // No prefix
|
|
786
|
+
expect(updatedUris).toContain("file:///home/user/doc2.txt");
|
|
787
|
+
expect(updatedUris).not.toContain("server-a:file:///home/user/doc1.txt"); // No prefix when only 1 server
|
|
788
|
+
expect(updatedUris).not.toContain("server-b:file:///workspace/code.js"); // Server B removed
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
describe("useTamboMcpResource - read individual resource", () => {
|
|
792
|
+
let queryClient;
|
|
793
|
+
beforeEach(() => {
|
|
794
|
+
createImpl = jest.fn();
|
|
795
|
+
queryClient = new react_query_1.QueryClient({
|
|
796
|
+
defaultOptions: {
|
|
797
|
+
queries: {
|
|
798
|
+
retry: false,
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
afterEach(() => {
|
|
804
|
+
queryClient.clear();
|
|
805
|
+
});
|
|
806
|
+
it("should read a resource from a single server (unprefixed)", async () => {
|
|
807
|
+
const serverAResources = {
|
|
808
|
+
resources: [
|
|
809
|
+
{
|
|
810
|
+
uri: "file:///home/user/doc.txt",
|
|
811
|
+
name: "Document",
|
|
812
|
+
mimeType: "text/plain",
|
|
813
|
+
},
|
|
814
|
+
],
|
|
815
|
+
};
|
|
816
|
+
const resourceContents = {
|
|
817
|
+
contents: [
|
|
818
|
+
{
|
|
819
|
+
uri: "file:///home/user/doc.txt",
|
|
820
|
+
mimeType: "text/plain",
|
|
821
|
+
text: "Hello, world!",
|
|
822
|
+
},
|
|
823
|
+
],
|
|
824
|
+
};
|
|
825
|
+
const mockClientA = {
|
|
826
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
827
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
828
|
+
listResources: jest.fn().mockResolvedValue(serverAResources),
|
|
829
|
+
readResource: jest.fn().mockResolvedValue(resourceContents),
|
|
830
|
+
close: jest.fn(),
|
|
831
|
+
};
|
|
832
|
+
const clientA = {
|
|
833
|
+
client: mockClientA,
|
|
834
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
835
|
+
close: jest.fn(),
|
|
836
|
+
};
|
|
837
|
+
createImpl.mockImplementation(async () => clientA);
|
|
838
|
+
let capturedResourceData = null;
|
|
839
|
+
const Capture = () => {
|
|
840
|
+
const { data: resourceData } = (0, mcp_hooks_1.useTamboMcpResource)("file:///home/user/doc.txt");
|
|
841
|
+
(0, react_2.useEffect)(() => {
|
|
842
|
+
if (resourceData) {
|
|
843
|
+
capturedResourceData = resourceData;
|
|
844
|
+
}
|
|
845
|
+
}, [resourceData]);
|
|
846
|
+
return null;
|
|
847
|
+
};
|
|
848
|
+
(0, react_1.render)(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
849
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
850
|
+
queryClient,
|
|
851
|
+
isUpdatingToken: false,
|
|
852
|
+
} },
|
|
853
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
854
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
855
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
856
|
+
{
|
|
857
|
+
url: "https://server-a.example",
|
|
858
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
859
|
+
},
|
|
860
|
+
] },
|
|
861
|
+
react_2.default.createElement(Capture, null))))));
|
|
862
|
+
await (0, react_1.waitFor)(() => {
|
|
863
|
+
expect(capturedResourceData).not.toBeNull();
|
|
864
|
+
});
|
|
865
|
+
expect(capturedResourceData.contents[0].text).toBe("Hello, world!");
|
|
866
|
+
expect(mockClientA.readResource).toHaveBeenCalledWith({
|
|
867
|
+
uri: "file:///home/user/doc.txt",
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
it("should read a resource from multiple servers (prefixed)", async () => {
|
|
871
|
+
const serverAResources = {
|
|
872
|
+
resources: [
|
|
873
|
+
{
|
|
874
|
+
uri: "file:///home/user/doc.txt",
|
|
875
|
+
name: "Document",
|
|
876
|
+
mimeType: "text/plain",
|
|
877
|
+
},
|
|
878
|
+
],
|
|
879
|
+
};
|
|
880
|
+
const serverBResources = {
|
|
881
|
+
resources: [
|
|
882
|
+
{
|
|
883
|
+
uri: "file:///workspace/code.js",
|
|
884
|
+
name: "Code",
|
|
885
|
+
mimeType: "text/javascript",
|
|
886
|
+
},
|
|
887
|
+
],
|
|
888
|
+
};
|
|
889
|
+
const resourceContentsA = {
|
|
890
|
+
contents: [
|
|
891
|
+
{
|
|
892
|
+
uri: "file:///home/user/doc.txt",
|
|
893
|
+
mimeType: "text/plain",
|
|
894
|
+
text: "From server A",
|
|
895
|
+
},
|
|
896
|
+
],
|
|
897
|
+
};
|
|
898
|
+
const mockClientA = {
|
|
899
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
900
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
901
|
+
listResources: jest.fn().mockResolvedValue(serverAResources),
|
|
902
|
+
readResource: jest.fn().mockResolvedValue(resourceContentsA),
|
|
903
|
+
close: jest.fn(),
|
|
904
|
+
};
|
|
905
|
+
const mockClientB = {
|
|
906
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
907
|
+
listPrompts: jest.fn().mockResolvedValue({ prompts: [] }),
|
|
908
|
+
listResources: jest.fn().mockResolvedValue(serverBResources),
|
|
909
|
+
close: jest.fn(),
|
|
910
|
+
};
|
|
911
|
+
const clientA = {
|
|
912
|
+
client: mockClientA,
|
|
913
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
914
|
+
close: jest.fn(),
|
|
915
|
+
};
|
|
916
|
+
const clientB = {
|
|
917
|
+
client: mockClientB,
|
|
918
|
+
listTools: jest.fn().mockResolvedValue([]),
|
|
919
|
+
close: jest.fn(),
|
|
920
|
+
};
|
|
921
|
+
createImpl.mockImplementation(async (url) => {
|
|
922
|
+
if (url === "https://server-a.example")
|
|
923
|
+
return clientA;
|
|
924
|
+
if (url === "https://server-b.example")
|
|
925
|
+
return clientB;
|
|
926
|
+
throw new Error(`Unexpected URL: ${url}`);
|
|
927
|
+
});
|
|
928
|
+
let capturedResourceData = null;
|
|
929
|
+
const Capture = () => {
|
|
930
|
+
// Request with prefix
|
|
931
|
+
const { data: resourceData } = (0, mcp_hooks_1.useTamboMcpResource)("server-a:file:///home/user/doc.txt");
|
|
932
|
+
(0, react_2.useEffect)(() => {
|
|
933
|
+
if (resourceData) {
|
|
934
|
+
capturedResourceData = resourceData;
|
|
935
|
+
}
|
|
936
|
+
}, [resourceData]);
|
|
937
|
+
return null;
|
|
938
|
+
};
|
|
939
|
+
(0, react_1.render)(react_2.default.createElement(tambo_client_provider_1.TamboClientContext.Provider, { value: {
|
|
940
|
+
client: { baseURL: "https://api.tambo.co" },
|
|
941
|
+
queryClient,
|
|
942
|
+
isUpdatingToken: false,
|
|
943
|
+
} },
|
|
944
|
+
react_2.default.createElement(tambo_registry_provider_1.TamboRegistryProvider, null,
|
|
945
|
+
react_2.default.createElement(tambo_mcp_token_provider_1.TamboMcpTokenProvider, null,
|
|
946
|
+
react_2.default.createElement(tambo_mcp_provider_1.TamboMcpProvider, { mcpServers: [
|
|
947
|
+
{
|
|
948
|
+
url: "https://server-a.example",
|
|
949
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
url: "https://server-b.example",
|
|
953
|
+
transport: mcp_client_1.MCPTransport.SSE,
|
|
954
|
+
},
|
|
955
|
+
] },
|
|
956
|
+
react_2.default.createElement(Capture, null))))));
|
|
957
|
+
await (0, react_1.waitFor)(() => {
|
|
958
|
+
expect(capturedResourceData).not.toBeNull();
|
|
959
|
+
});
|
|
960
|
+
expect(capturedResourceData.contents[0].text).toBe("From server A");
|
|
961
|
+
// Verify the prefix was stripped before calling the server
|
|
962
|
+
expect(mockClientA.readResource).toHaveBeenCalledWith({
|
|
963
|
+
uri: "file:///home/user/doc.txt",
|
|
964
|
+
});
|
|
502
965
|
});
|
|
503
966
|
});
|
|
504
967
|
//# sourceMappingURL=mcp-hooks.test.js.map
|