@tambo-ai/react 0.67.1 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +2 -4
  2. package/dist/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  3. package/dist/context-helpers/current-interactables-context-helper.js +4 -1
  4. package/dist/context-helpers/current-interactables-context-helper.js.map +1 -1
  5. package/dist/hoc/with-tambo-interactable.d.ts +50 -4
  6. package/dist/hoc/with-tambo-interactable.d.ts.map +1 -1
  7. package/dist/hoc/with-tambo-interactable.js +20 -5
  8. package/dist/hoc/with-tambo-interactable.js.map +1 -1
  9. package/dist/hooks/use-component-state.d.ts +3 -8
  10. package/dist/hooks/use-component-state.d.ts.map +1 -1
  11. package/dist/hooks/use-component-state.js +8 -0
  12. package/dist/hooks/use-component-state.js.map +1 -1
  13. package/dist/hooks/use-component-state.test.js +37 -0
  14. package/dist/hooks/use-component-state.test.js.map +1 -1
  15. package/dist/hooks/use-tambo-threads.js +1 -1
  16. package/dist/hooks/use-tambo-threads.js.map +1 -1
  17. package/dist/mcp/mcp-constants.d.ts +19 -0
  18. package/dist/mcp/mcp-constants.d.ts.map +1 -0
  19. package/dist/mcp/mcp-constants.js +21 -0
  20. package/dist/mcp/mcp-constants.js.map +1 -0
  21. package/dist/mcp/mcp-hooks.d.ts +32 -3
  22. package/dist/mcp/mcp-hooks.d.ts.map +1 -1
  23. package/dist/mcp/mcp-hooks.js +40 -29
  24. package/dist/mcp/mcp-hooks.js.map +1 -1
  25. package/dist/mcp/mcp-hooks.test.js +8 -5
  26. package/dist/mcp/mcp-hooks.test.js.map +1 -1
  27. package/dist/mcp/tambo-mcp-provider.d.ts +7 -0
  28. package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
  29. package/dist/mcp/tambo-mcp-provider.js +202 -155
  30. package/dist/mcp/tambo-mcp-provider.js.map +1 -1
  31. package/dist/model/component-metadata.d.ts +1 -1
  32. package/dist/model/component-metadata.d.ts.map +1 -1
  33. package/dist/model/component-metadata.js.map +1 -1
  34. package/dist/model/tambo-interactable.d.ts +7 -5
  35. package/dist/model/tambo-interactable.d.ts.map +1 -1
  36. package/dist/model/tambo-interactable.js.map +1 -1
  37. package/dist/providers/__tests__/thread-input-resource-resolution.test.d.ts +2 -0
  38. package/dist/providers/__tests__/thread-input-resource-resolution.test.d.ts.map +1 -0
  39. package/dist/providers/__tests__/thread-input-resource-resolution.test.js +592 -0
  40. package/dist/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -0
  41. package/dist/providers/tambo-interactable-provider-partial-updates.test.js +22 -21
  42. package/dist/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  43. package/dist/providers/tambo-interactable-provider.d.ts +3 -2
  44. package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
  45. package/dist/providers/tambo-interactable-provider.js +98 -14
  46. package/dist/providers/tambo-interactable-provider.js.map +1 -1
  47. package/dist/providers/tambo-interactable-provider.test.js +242 -0
  48. package/dist/providers/tambo-interactable-provider.test.js.map +1 -1
  49. package/dist/providers/tambo-provider.d.ts.map +1 -1
  50. package/dist/providers/tambo-provider.js +7 -5
  51. package/dist/providers/tambo-provider.js.map +1 -1
  52. package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
  53. package/dist/providers/tambo-thread-input-provider.js +21 -3
  54. package/dist/providers/tambo-thread-input-provider.js.map +1 -1
  55. package/dist/schema/index.d.ts +1 -1
  56. package/dist/schema/index.d.ts.map +1 -1
  57. package/dist/schema/index.js +2 -1
  58. package/dist/schema/index.js.map +1 -1
  59. package/dist/schema/json-schema.d.ts +7 -0
  60. package/dist/schema/json-schema.d.ts.map +1 -1
  61. package/dist/schema/json-schema.js +11 -0
  62. package/dist/schema/json-schema.js.map +1 -1
  63. package/dist/schema/json-schema.test.d.ts +2 -0
  64. package/dist/schema/json-schema.test.d.ts.map +1 -0
  65. package/dist/schema/json-schema.test.js +204 -0
  66. package/dist/schema/json-schema.test.js.map +1 -0
  67. package/dist/setupTests.js +3 -0
  68. package/dist/setupTests.js.map +1 -1
  69. package/dist/util/message-builder.d.ts +3 -1
  70. package/dist/util/message-builder.d.ts.map +1 -1
  71. package/dist/util/message-builder.js +20 -3
  72. package/dist/util/message-builder.js.map +1 -1
  73. package/dist/util/message-builder.test.js +269 -0
  74. package/dist/util/message-builder.test.js.map +1 -1
  75. package/dist/util/resource-content-resolver.d.ts +20 -0
  76. package/dist/util/resource-content-resolver.d.ts.map +1 -0
  77. package/dist/util/resource-content-resolver.js +93 -0
  78. package/dist/util/resource-content-resolver.js.map +1 -0
  79. package/dist/util/resource-content-resolver.test.d.ts +2 -0
  80. package/dist/util/resource-content-resolver.test.d.ts.map +1 -0
  81. package/dist/util/resource-content-resolver.test.js +254 -0
  82. package/dist/util/resource-content-resolver.test.js.map +1 -0
  83. package/esm/context-helpers/current-interactables-context-helper.d.ts.map +1 -1
  84. package/esm/context-helpers/current-interactables-context-helper.js +4 -1
  85. package/esm/context-helpers/current-interactables-context-helper.js.map +1 -1
  86. package/esm/hoc/with-tambo-interactable.d.ts +50 -4
  87. package/esm/hoc/with-tambo-interactable.d.ts.map +1 -1
  88. package/esm/hoc/with-tambo-interactable.js +20 -5
  89. package/esm/hoc/with-tambo-interactable.js.map +1 -1
  90. package/esm/hooks/use-component-state.d.ts +3 -8
  91. package/esm/hooks/use-component-state.d.ts.map +1 -1
  92. package/esm/hooks/use-component-state.js +8 -0
  93. package/esm/hooks/use-component-state.js.map +1 -1
  94. package/esm/hooks/use-component-state.test.js +37 -0
  95. package/esm/hooks/use-component-state.test.js.map +1 -1
  96. package/esm/hooks/use-tambo-threads.js +1 -1
  97. package/esm/hooks/use-tambo-threads.js.map +1 -1
  98. package/esm/mcp/mcp-constants.d.ts +19 -0
  99. package/esm/mcp/mcp-constants.d.ts.map +1 -0
  100. package/esm/mcp/mcp-constants.js +18 -0
  101. package/esm/mcp/mcp-constants.js.map +1 -0
  102. package/esm/mcp/mcp-hooks.d.ts +32 -3
  103. package/esm/mcp/mcp-hooks.d.ts.map +1 -1
  104. package/esm/mcp/mcp-hooks.js +40 -30
  105. package/esm/mcp/mcp-hooks.js.map +1 -1
  106. package/esm/mcp/mcp-hooks.test.js +8 -5
  107. package/esm/mcp/mcp-hooks.test.js.map +1 -1
  108. package/esm/mcp/tambo-mcp-provider.d.ts +7 -0
  109. package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
  110. package/esm/mcp/tambo-mcp-provider.js +201 -154
  111. package/esm/mcp/tambo-mcp-provider.js.map +1 -1
  112. package/esm/model/component-metadata.d.ts +1 -1
  113. package/esm/model/component-metadata.d.ts.map +1 -1
  114. package/esm/model/component-metadata.js.map +1 -1
  115. package/esm/model/tambo-interactable.d.ts +7 -5
  116. package/esm/model/tambo-interactable.d.ts.map +1 -1
  117. package/esm/model/tambo-interactable.js.map +1 -1
  118. package/esm/providers/__tests__/thread-input-resource-resolution.test.d.ts +2 -0
  119. package/esm/providers/__tests__/thread-input-resource-resolution.test.d.ts.map +1 -0
  120. package/esm/providers/__tests__/thread-input-resource-resolution.test.js +587 -0
  121. package/esm/providers/__tests__/thread-input-resource-resolution.test.js.map +1 -0
  122. package/esm/providers/tambo-interactable-provider-partial-updates.test.js +22 -21
  123. package/esm/providers/tambo-interactable-provider-partial-updates.test.js.map +1 -1
  124. package/esm/providers/tambo-interactable-provider.d.ts +3 -2
  125. package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
  126. package/esm/providers/tambo-interactable-provider.js +98 -14
  127. package/esm/providers/tambo-interactable-provider.js.map +1 -1
  128. package/esm/providers/tambo-interactable-provider.test.js +242 -0
  129. package/esm/providers/tambo-interactable-provider.test.js.map +1 -1
  130. package/esm/providers/tambo-provider.d.ts.map +1 -1
  131. package/esm/providers/tambo-provider.js +7 -5
  132. package/esm/providers/tambo-provider.js.map +1 -1
  133. package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
  134. package/esm/providers/tambo-thread-input-provider.js +21 -3
  135. package/esm/providers/tambo-thread-input-provider.js.map +1 -1
  136. package/esm/schema/index.d.ts +1 -1
  137. package/esm/schema/index.d.ts.map +1 -1
  138. package/esm/schema/index.js +1 -1
  139. package/esm/schema/index.js.map +1 -1
  140. package/esm/schema/json-schema.d.ts +7 -0
  141. package/esm/schema/json-schema.d.ts.map +1 -1
  142. package/esm/schema/json-schema.js +10 -0
  143. package/esm/schema/json-schema.js.map +1 -1
  144. package/esm/schema/json-schema.test.d.ts +2 -0
  145. package/esm/schema/json-schema.test.d.ts.map +1 -0
  146. package/esm/schema/json-schema.test.js +202 -0
  147. package/esm/schema/json-schema.test.js.map +1 -0
  148. package/esm/setupTests.js +3 -0
  149. package/esm/setupTests.js.map +1 -1
  150. package/esm/util/message-builder.d.ts +3 -1
  151. package/esm/util/message-builder.d.ts.map +1 -1
  152. package/esm/util/message-builder.js +20 -3
  153. package/esm/util/message-builder.js.map +1 -1
  154. package/esm/util/message-builder.test.js +269 -0
  155. package/esm/util/message-builder.test.js.map +1 -1
  156. package/esm/util/resource-content-resolver.d.ts +20 -0
  157. package/esm/util/resource-content-resolver.d.ts.map +1 -0
  158. package/esm/util/resource-content-resolver.js +89 -0
  159. package/esm/util/resource-content-resolver.js.map +1 -0
  160. package/esm/util/resource-content-resolver.test.d.ts +2 -0
  161. package/esm/util/resource-content-resolver.test.d.ts.map +1 -0
  162. package/esm/util/resource-content-resolver.test.js +252 -0
  163. package/esm/util/resource-content-resolver.test.js.map +1 -0
  164. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tambo-thread-input-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-thread-input-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useState,\n} from \"react\";\nimport {\n useTamboMutation,\n UseTamboMutationResult,\n} from \"../hooks/react-query-hooks\";\nimport { StagedImage, useMessageImages } from \"../hooks/use-message-images\";\nimport { ThreadInputError } from \"../model/thread-input-error\";\nimport { validateInput } from \"../model/validate-input\";\nimport { buildMessageContent } from \"../util/message-builder\";\nimport { useTamboThread } from \"./tambo-thread-provider\";\n\n/**\n * Error messages for various input-related error scenarios\n * These messages are used to provide user-friendly error feedback\n * @readonly\n */\nexport const INPUT_ERROR_MESSAGES = {\n EMPTY: \"Message cannot be empty\",\n NETWORK: \"Network error. Please check your connection\",\n SERVER: \"Server error. Please try again\",\n VALIDATION: \"Invalid message format\",\n} as const;\n\nexport interface TamboThreadInputContextProps extends Omit<\n UseTamboMutationResult<\n void,\n Error,\n | {\n contextKey?: string;\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n }\n | undefined\n >,\n \"mutate\" | \"mutateAsync\"\n> {\n /** Current value of the input field */\n value: string;\n /**\n * Function to update the input value\n * @param value - New value for the input field\n */\n setValue: (value: string) => void;\n /**\n * Function to submit the current input value\n * @param options - Submission options\n */\n submit: (options?: {\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n resourceNames?: Record<string, string>;\n }) => Promise<void>;\n /** Currently staged images */\n images: StagedImage[];\n /** Add a single image */\n addImage: (file: File) => Promise<void>;\n /** Add multiple images */\n addImages: (files: File[]) => Promise<void>;\n /** Remove an image by id */\n removeImage: (id: string) => void;\n /** Clear all staged images */\n clearImages: () => void;\n}\n\nexport const TamboThreadInputContext = createContext<\n TamboThreadInputContextProps | undefined\n>(undefined);\n\n/**\n * Provider that manages shared thread input state across all components\n * This ensures that useTamboThreadInput, useTamboSuggestions, and components\n * all share the same input state\n * @param props - The props for the TamboThreadInputProvider\n * @param props.children - The children to render.\n * @returns The thread input context\n */\nexport const TamboThreadInputProvider: React.FC<PropsWithChildren> = ({\n children,\n}) => {\n const { thread, sendThreadMessage, contextKey } = useTamboThread();\n const [inputValue, setInputValue] = useState(\"\");\n const imageState = useMessageImages();\n\n const submit = useCallback(\n async ({\n streamResponse,\n forceToolChoice,\n additionalContext,\n resourceNames = {},\n }: {\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n resourceNames?: Record<string, string>;\n } = {}) => {\n // Validate text input if present\n if (inputValue?.trim()) {\n const validation = validateInput(inputValue);\n if (!validation.isValid) {\n throw new ThreadInputError(\n `Cannot submit message: ${validation.error ?? INPUT_ERROR_MESSAGES.VALIDATION}`,\n { cause: validation.error },\n );\n }\n }\n\n // Check if we have content to send\n if (!inputValue.trim() && imageState.images.length === 0) {\n throw new ThreadInputError(INPUT_ERROR_MESSAGES.EMPTY, {\n cause: \"No text or images to send\",\n });\n }\n\n // Build message content with text, images, and resource names\n const messageContent = buildMessageContent(\n inputValue,\n imageState.images,\n resourceNames,\n );\n\n try {\n await sendThreadMessage(inputValue || \"Image message\", {\n threadId: thread.id,\n contextKey,\n streamResponse: streamResponse,\n forceToolChoice: forceToolChoice,\n additionalContext: additionalContext,\n content: messageContent,\n });\n } catch (error: any) {\n // Handle image-related errors with friendly messages\n if (imageState.images.length > 0) {\n const errorMessage = error?.message?.toLowerCase() ?? \"\";\n\n // Backend not yet supporting image content type\n if (errorMessage.includes(\"unknown content part type: image\")) {\n throw new ThreadInputError(\n \"Image attachments are not yet supported by the backend. This feature is coming soon.\",\n { cause: error },\n );\n }\n\n // Handle specific model vision support errors\n // OpenAI errors\n if (\n errorMessage.includes(\n \"does not support image message content types\",\n ) ||\n (errorMessage.includes(\"invalid model\") &&\n errorMessage.includes(\n \"image_url is only supported by certain models\",\n ))\n ) {\n throw new ThreadInputError(\n \"This model doesn't support images. Please use GPT-4o, GPT-4 Turbo, or other vision-capable models.\",\n { cause: error },\n );\n }\n\n // Anthropic Claude errors\n if (\n errorMessage.includes(\"does not support image\") ||\n errorMessage.includes(\"vision not supported\")\n ) {\n throw new ThreadInputError(\n \"This Claude model doesn't support images. Please use Claude 3.5 Sonnet, Claude 3 Opus, or other vision-capable models.\",\n { cause: error },\n );\n }\n\n // Generic image/vision errors\n if (\n errorMessage.includes(\"image\") ||\n errorMessage.includes(\"vision\")\n ) {\n throw new ThreadInputError(\n \"This model doesn't support image attachments. Please use a vision-capable model.\",\n { cause: error },\n );\n }\n }\n\n throw error;\n }\n\n // Clear text after successful submission\n setInputValue(\"\");\n },\n [inputValue, sendThreadMessage, thread.id, contextKey, imageState],\n );\n\n const {\n mutateAsync: submitAsync,\n mutate: _unusedSubmit,\n ...mutationState\n } = useTamboMutation({\n mutationFn: submit,\n });\n\n const value = {\n ...mutationState,\n value: inputValue,\n setValue: setInputValue,\n submit: submitAsync,\n images: imageState.images,\n addImage: imageState.addImage,\n addImages: imageState.addImages,\n removeImage: imageState.removeImage,\n clearImages: imageState.clearImages,\n };\n\n return (\n <TamboThreadInputContext.Provider value={value}>\n {children}\n </TamboThreadInputContext.Provider>\n );\n};\n\n/**\n * Hook to access the shared thread input state\n * contextKey parameter is not passed here anymore. Instead, use the contextKey prop in the TamboProvider.\n * @returns The thread input context\n */\nexport const useTamboThreadInput = () => {\n const context = useContext(TamboThreadInputContext);\n if (!context) {\n throw new Error(\n \"useTamboThreadInput must be used within a TamboThreadInputProvider\",\n );\n }\n\n return context;\n};\n"]}
1
+ {"version":3,"file":"tambo-thread-input-provider.js","sourceRoot":"","sources":["../../src/providers/tambo-thread-input-provider.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useState,\n} from \"react\";\nimport {\n useTamboMutation,\n UseTamboMutationResult,\n} from \"../hooks/react-query-hooks\";\nimport { StagedImage, useMessageImages } from \"../hooks/use-message-images\";\nimport { useTamboMcpServers } from \"../mcp/tambo-mcp-provider\";\nimport { ThreadInputError } from \"../model/thread-input-error\";\nimport { validateInput } from \"../model/validate-input\";\nimport { buildMessageContent } from \"../util/message-builder\";\nimport {\n extractResourceUris,\n resolveResourceContents,\n} from \"../util/resource-content-resolver\";\nimport { useTamboRegistry } from \"./tambo-registry-provider\";\nimport { useTamboThread } from \"./tambo-thread-provider\";\n\n/**\n * Error messages for various input-related error scenarios\n * These messages are used to provide user-friendly error feedback\n * @readonly\n */\nexport const INPUT_ERROR_MESSAGES = {\n EMPTY: \"Message cannot be empty\",\n NETWORK: \"Network error. Please check your connection\",\n SERVER: \"Server error. Please try again\",\n VALIDATION: \"Invalid message format\",\n} as const;\n\nexport interface TamboThreadInputContextProps extends Omit<\n UseTamboMutationResult<\n void,\n Error,\n | {\n contextKey?: string;\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n }\n | undefined\n >,\n \"mutate\" | \"mutateAsync\"\n> {\n /** Current value of the input field */\n value: string;\n /**\n * Function to update the input value\n * @param value - New value for the input field\n */\n setValue: (value: string) => void;\n /**\n * Function to submit the current input value\n * @param options - Submission options\n */\n submit: (options?: {\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n resourceNames?: Record<string, string>;\n }) => Promise<void>;\n /** Currently staged images */\n images: StagedImage[];\n /** Add a single image */\n addImage: (file: File) => Promise<void>;\n /** Add multiple images */\n addImages: (files: File[]) => Promise<void>;\n /** Remove an image by id */\n removeImage: (id: string) => void;\n /** Clear all staged images */\n clearImages: () => void;\n}\n\nexport const TamboThreadInputContext = createContext<\n TamboThreadInputContextProps | undefined\n>(undefined);\n\n/**\n * Provider that manages shared thread input state across all components\n * This ensures that useTamboThreadInput, useTamboSuggestions, and components\n * all share the same input state\n * @param props - The props for the TamboThreadInputProvider\n * @param props.children - The children to render.\n * @returns The thread input context\n */\nexport const TamboThreadInputProvider: React.FC<PropsWithChildren> = ({\n children,\n}) => {\n const { thread, sendThreadMessage, contextKey } = useTamboThread();\n const [inputValue, setInputValue] = useState(\"\");\n const imageState = useMessageImages();\n const mcpServers = useTamboMcpServers();\n const { resourceSource } = useTamboRegistry();\n\n const submit = useCallback(\n async ({\n streamResponse,\n forceToolChoice,\n additionalContext,\n resourceNames = {},\n }: {\n streamResponse?: boolean;\n forceToolChoice?: string;\n additionalContext?: Record<string, any>;\n resourceNames?: Record<string, string>;\n } = {}) => {\n // Validate text input if present\n if (inputValue?.trim()) {\n const validation = validateInput(inputValue);\n if (!validation.isValid) {\n throw new ThreadInputError(\n `Cannot submit message: ${validation.error ?? INPUT_ERROR_MESSAGES.VALIDATION}`,\n { cause: validation.error },\n );\n }\n }\n\n // Check if we have content to send\n if (!inputValue.trim() && imageState.images.length === 0) {\n throw new ThreadInputError(INPUT_ERROR_MESSAGES.EMPTY, {\n cause: \"No text or images to send\",\n });\n }\n\n // Extract resource URIs from the input text and resolve content for client-side resources\n // (registry and client-side MCP servers). Internal Tambo server resources are skipped\n // since the backend can resolve them.\n const resourceUris = extractResourceUris(inputValue);\n const resolvedContent = await resolveResourceContents(\n resourceUris,\n mcpServers,\n resourceSource ?? undefined,\n );\n\n // Build message content with text, images, resource names, and resolved content\n const messageContent = buildMessageContent(\n inputValue,\n imageState.images,\n resourceNames,\n resolvedContent,\n );\n\n try {\n await sendThreadMessage(inputValue || \"Image message\", {\n threadId: thread.id,\n contextKey,\n streamResponse: streamResponse,\n forceToolChoice: forceToolChoice,\n additionalContext: additionalContext,\n content: messageContent,\n });\n } catch (error: any) {\n // Handle image-related errors with friendly messages\n if (imageState.images.length > 0) {\n const errorMessage = error?.message?.toLowerCase() ?? \"\";\n\n // Backend not yet supporting image content type\n if (errorMessage.includes(\"unknown content part type: image\")) {\n throw new ThreadInputError(\n \"Image attachments are not yet supported by the backend. This feature is coming soon.\",\n { cause: error },\n );\n }\n\n // Handle specific model vision support errors\n // OpenAI errors\n if (\n errorMessage.includes(\n \"does not support image message content types\",\n ) ||\n (errorMessage.includes(\"invalid model\") &&\n errorMessage.includes(\n \"image_url is only supported by certain models\",\n ))\n ) {\n throw new ThreadInputError(\n \"This model doesn't support images. Please use GPT-4o, GPT-4 Turbo, or other vision-capable models.\",\n { cause: error },\n );\n }\n\n // Anthropic Claude errors\n if (\n errorMessage.includes(\"does not support image\") ||\n errorMessage.includes(\"vision not supported\")\n ) {\n throw new ThreadInputError(\n \"This Claude model doesn't support images. Please use Claude 3.5 Sonnet, Claude 3 Opus, or other vision-capable models.\",\n { cause: error },\n );\n }\n\n // Generic image/vision errors\n if (\n errorMessage.includes(\"image\") ||\n errorMessage.includes(\"vision\")\n ) {\n throw new ThreadInputError(\n \"This model doesn't support image attachments. Please use a vision-capable model.\",\n { cause: error },\n );\n }\n }\n\n throw error;\n }\n\n // Clear text after successful submission\n setInputValue(\"\");\n },\n [\n inputValue,\n sendThreadMessage,\n thread.id,\n contextKey,\n imageState,\n mcpServers,\n resourceSource,\n ],\n );\n\n const {\n mutateAsync: submitAsync,\n mutate: _unusedSubmit,\n ...mutationState\n } = useTamboMutation({\n mutationFn: submit,\n });\n\n const value = {\n ...mutationState,\n value: inputValue,\n setValue: setInputValue,\n submit: submitAsync,\n images: imageState.images,\n addImage: imageState.addImage,\n addImages: imageState.addImages,\n removeImage: imageState.removeImage,\n clearImages: imageState.clearImages,\n };\n\n return (\n <TamboThreadInputContext.Provider value={value}>\n {children}\n </TamboThreadInputContext.Provider>\n );\n};\n\n/**\n * Hook to access the shared thread input state\n * contextKey parameter is not passed here anymore. Instead, use the contextKey prop in the TamboProvider.\n * @returns The thread input context\n */\nexport const useTamboThreadInput = () => {\n const context = useContext(TamboThreadInputContext);\n if (!context) {\n throw new Error(\n \"useTamboThreadInput must be used within a TamboThreadInputProvider\",\n );\n }\n\n return context;\n};\n"]}
@@ -1,4 +1,4 @@
1
- export { looksLikeJSONSchema } from "./json-schema";
1
+ export { looksLikeJSONSchema, makeJsonSchemaPartial } from "./json-schema";
2
2
  export { getParametersFromToolSchema, hasInputSchema, safeSchemaToJsonSchema, schemaToJsonSchema, type SupportedSchema, } from "./schema";
3
3
  export { isStandardSchema } from "./standard-schema";
4
4
  export { assertNoRecordSchema } from "./validate";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,2BAA2B,EAC3B,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EACL,2BAA2B,EAC3B,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC"}
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getZodFunctionReturns = exports.getZodFunctionArgs = exports.assertNoRecordSchema = exports.isStandardSchema = exports.schemaToJsonSchema = exports.safeSchemaToJsonSchema = exports.hasInputSchema = exports.getParametersFromToolSchema = exports.looksLikeJSONSchema = void 0;
3
+ exports.getZodFunctionReturns = exports.getZodFunctionArgs = exports.assertNoRecordSchema = exports.isStandardSchema = exports.schemaToJsonSchema = exports.safeSchemaToJsonSchema = exports.hasInputSchema = exports.getParametersFromToolSchema = exports.makeJsonSchemaPartial = exports.looksLikeJSONSchema = void 0;
4
4
  var json_schema_1 = require("./json-schema");
5
5
  Object.defineProperty(exports, "looksLikeJSONSchema", { enumerable: true, get: function () { return json_schema_1.looksLikeJSONSchema; } });
6
+ Object.defineProperty(exports, "makeJsonSchemaPartial", { enumerable: true, get: function () { return json_schema_1.makeJsonSchemaPartial; } });
6
7
  var schema_1 = require("./schema");
7
8
  Object.defineProperty(exports, "getParametersFromToolSchema", { enumerable: true, get: function () { return schema_1.getParametersFromToolSchema; } });
8
9
  Object.defineProperty(exports, "hasInputSchema", { enumerable: true, get: function () { return schema_1.hasInputSchema; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":";;;AAAA,6CAAoD;AAA3C,kHAAA,mBAAmB,OAAA;AAC5B,mCAMkB;AALhB,qHAAA,2BAA2B,OAAA;AAC3B,wGAAA,cAAc,OAAA;AACd,gHAAA,sBAAsB,OAAA;AACtB,4GAAA,kBAAkB,OAAA;AAGpB,qDAAqD;AAA5C,mHAAA,gBAAgB,OAAA;AACzB,uCAAkD;AAAzC,gHAAA,oBAAoB,OAAA;AAC7B,6BAAkE;AAAzD,yGAAA,kBAAkB,OAAA;AAAE,4GAAA,qBAAqB,OAAA","sourcesContent":["export { looksLikeJSONSchema } from \"./json-schema\";\nexport {\n getParametersFromToolSchema,\n hasInputSchema,\n safeSchemaToJsonSchema,\n schemaToJsonSchema,\n type SupportedSchema,\n} from \"./schema\";\nexport { isStandardSchema } from \"./standard-schema\";\nexport { assertNoRecordSchema } from \"./validate\";\nexport { getZodFunctionArgs, getZodFunctionReturns } from \"./zod\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":";;;AAAA,6CAA2E;AAAlE,kHAAA,mBAAmB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AACnD,mCAMkB;AALhB,qHAAA,2BAA2B,OAAA;AAC3B,wGAAA,cAAc,OAAA;AACd,gHAAA,sBAAsB,OAAA;AACtB,4GAAA,kBAAkB,OAAA;AAGpB,qDAAqD;AAA5C,mHAAA,gBAAgB,OAAA;AACzB,uCAAkD;AAAzC,gHAAA,oBAAoB,OAAA;AAC7B,6BAAkE;AAAzD,yGAAA,kBAAkB,OAAA;AAAE,4GAAA,qBAAqB,OAAA","sourcesContent":["export { looksLikeJSONSchema, makeJsonSchemaPartial } from \"./json-schema\";\nexport {\n getParametersFromToolSchema,\n hasInputSchema,\n safeSchemaToJsonSchema,\n schemaToJsonSchema,\n type SupportedSchema,\n} from \"./schema\";\nexport { isStandardSchema } from \"./standard-schema\";\nexport { assertNoRecordSchema } from \"./validate\";\nexport { getZodFunctionArgs, getZodFunctionReturns } from \"./zod\";\n"]}
@@ -32,4 +32,11 @@ export declare function isJsonSchemaTuple(schema: JSONSchema7Extended): schema i
32
32
  * @returns Array of item schemas, or undefined if not a tuple
33
33
  */
34
34
  export declare function getJsonSchemaTupleItems(schema: JSONSchema7Extended): JSONSchema7[] | undefined;
35
+ /**
36
+ * Creates a partial version of a JSON Schema by removing required constraints.
37
+ * This allows LLM to provide only the properties it wants to update.
38
+ * @param schema - The JSON Schema to make partial
39
+ * @returns A new JSON Schema with the required constraint removed
40
+ */
41
+ export declare function makeJsonSchemaPartial(schema: JSONSchema7): JSONSchema7;
35
42
  //# sourceMappingURL=json-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../../src/schema/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkD1C;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,WAAW,CAMpE;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC9C,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,mBAAmB,GAC1B,MAAM,IAAI,mBAAmB,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAgBnD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,mBAAmB,GAC1B,WAAW,EAAE,GAAG,SAAS,CAgB3B"}
1
+ {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../../src/schema/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkD1C;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,WAAW,CAMpE;AAED;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC9C,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,mBAAmB,GAC1B,MAAM,IAAI,mBAAmB,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAgBnD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,mBAAmB,GAC1B,WAAW,EAAE,GAAG,SAAS,CAgB3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAGtE"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.looksLikeJSONSchema = looksLikeJSONSchema;
4
4
  exports.isJsonSchemaTuple = isJsonSchemaTuple;
5
5
  exports.getJsonSchemaTupleItems = getJsonSchemaTupleItems;
6
+ exports.makeJsonSchemaPartial = makeJsonSchemaPartial;
6
7
  const alias_1 = require("./alias");
7
8
  const jsonSchemaType = alias_1.z.union([
8
9
  alias_1.z.literal("object"),
@@ -100,4 +101,14 @@ function getJsonSchemaTupleItems(schema) {
100
101
  }
101
102
  return undefined;
102
103
  }
104
+ /**
105
+ * Creates a partial version of a JSON Schema by removing required constraints.
106
+ * This allows LLM to provide only the properties it wants to update.
107
+ * @param schema - The JSON Schema to make partial
108
+ * @returns A new JSON Schema with the required constraint removed
109
+ */
110
+ function makeJsonSchemaPartial(schema) {
111
+ const { required: _required, ...rest } = schema;
112
+ return rest;
113
+ }
103
114
  //# sourceMappingURL=json-schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../../src/schema/json-schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { JSONSchema7 } from \"json-schema\";\nimport { z } from \"./alias\";\n\nconst jsonSchemaType = z.union([\n z.literal(\"object\"),\n z.literal(\"array\"),\n z.literal(\"string\"),\n z.literal(\"number\"),\n z.literal(\"integer\"),\n z.literal(\"boolean\"),\n z.literal(\"null\"),\n z.array(\n z.union([\n z.literal(\"object\"),\n z.literal(\"array\"),\n z.literal(\"string\"),\n z.literal(\"number\"),\n z.literal(\"integer\"),\n z.literal(\"boolean\"),\n z.literal(\"null\"),\n ]),\n ),\n]);\n\nconst jsonSchemaTopLevel = z\n .looseObject({\n type: jsonSchemaType.optional(),\n properties: z.record(z.string(), z.unknown()).optional(),\n items: z.union([z.array(z.unknown()), z.unknown()]).optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.union([z.boolean(), z.unknown()]).optional(),\n enum: z.array(z.unknown()).optional(),\n const: z.unknown().optional(),\n $ref: z.string().optional(),\n $id: z.string().optional(),\n $schema: z.string().optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n })\n .refine((value) => {\n return (\n value.type !== undefined ||\n value.properties !== undefined ||\n value.items !== undefined ||\n value.enum !== undefined ||\n value.const !== undefined ||\n value.$ref !== undefined\n );\n });\n\n/**\n * Basic heuristic to check if an object looks like a JSON Schema at the top level.\n *\n * This uses a Zod schema to verify only top-level keys (type, properties, items,\n * etc.). It intentionally does not perform full JSON Schema validation; a more\n * thorough check should be done server-side.\n * @param obj - The value to check\n * @returns True if the value appears to be a JSON Schema\n */\nexport function looksLikeJSONSchema(obj: unknown): obj is JSONSchema7 {\n if (obj === null || typeof obj !== \"object\") {\n return false;\n }\n\n return jsonSchemaTopLevel.safeParse(obj).success;\n}\n\n/**\n * Extended JSON Schema type that includes draft 2020-12 features like prefixItems.\n * The json-schema package types are from draft-07 and don't include prefixItems.\n */\nexport type JSONSchema7Extended = JSONSchema7 & {\n prefixItems?: JSONSchema7[];\n};\n\n/**\n * Checks if a JSON Schema represents a tuple (array with positional items).\n * Supports both draft-07 (items as array) and draft 2020-12 (prefixItems).\n * @param schema - The JSON Schema to check\n * @returns True if the schema represents a tuple\n */\nexport function isJsonSchemaTuple(\n schema: JSONSchema7Extended,\n): schema is JSONSchema7Extended & { type: \"array\" } {\n if (schema.type !== \"array\") {\n return false;\n }\n\n // Draft 2020-12: prefixItems array\n if (schema.prefixItems && Array.isArray(schema.prefixItems)) {\n return true;\n }\n\n // Draft-07: items as array (not object)\n if (Array.isArray(schema.items)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Gets the tuple items from a JSON Schema.\n * Supports both draft-07 (items as array) and draft 2020-12 (prefixItems).\n * @param schema - The JSON Schema tuple\n * @returns Array of item schemas, or undefined if not a tuple\n */\nexport function getJsonSchemaTupleItems(\n schema: JSONSchema7Extended,\n): JSONSchema7[] | undefined {\n if (schema.type !== \"array\") {\n return undefined;\n }\n\n // Draft 2020-12: prefixItems array\n if (schema.prefixItems && Array.isArray(schema.prefixItems)) {\n return schema.prefixItems;\n }\n\n // Draft-07: items as array\n if (Array.isArray(schema.items)) {\n return schema.items as JSONSchema7[];\n }\n\n return undefined;\n}\n"]}
1
+ {"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../../src/schema/json-schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { JSONSchema7 } from \"json-schema\";\nimport { z } from \"./alias\";\n\nconst jsonSchemaType = z.union([\n z.literal(\"object\"),\n z.literal(\"array\"),\n z.literal(\"string\"),\n z.literal(\"number\"),\n z.literal(\"integer\"),\n z.literal(\"boolean\"),\n z.literal(\"null\"),\n z.array(\n z.union([\n z.literal(\"object\"),\n z.literal(\"array\"),\n z.literal(\"string\"),\n z.literal(\"number\"),\n z.literal(\"integer\"),\n z.literal(\"boolean\"),\n z.literal(\"null\"),\n ]),\n ),\n]);\n\nconst jsonSchemaTopLevel = z\n .looseObject({\n type: jsonSchemaType.optional(),\n properties: z.record(z.string(), z.unknown()).optional(),\n items: z.union([z.array(z.unknown()), z.unknown()]).optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.union([z.boolean(), z.unknown()]).optional(),\n enum: z.array(z.unknown()).optional(),\n const: z.unknown().optional(),\n $ref: z.string().optional(),\n $id: z.string().optional(),\n $schema: z.string().optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n })\n .refine((value) => {\n return (\n value.type !== undefined ||\n value.properties !== undefined ||\n value.items !== undefined ||\n value.enum !== undefined ||\n value.const !== undefined ||\n value.$ref !== undefined\n );\n });\n\n/**\n * Basic heuristic to check if an object looks like a JSON Schema at the top level.\n *\n * This uses a Zod schema to verify only top-level keys (type, properties, items,\n * etc.). It intentionally does not perform full JSON Schema validation; a more\n * thorough check should be done server-side.\n * @param obj - The value to check\n * @returns True if the value appears to be a JSON Schema\n */\nexport function looksLikeJSONSchema(obj: unknown): obj is JSONSchema7 {\n if (obj === null || typeof obj !== \"object\") {\n return false;\n }\n\n return jsonSchemaTopLevel.safeParse(obj).success;\n}\n\n/**\n * Extended JSON Schema type that includes draft 2020-12 features like prefixItems.\n * The json-schema package types are from draft-07 and don't include prefixItems.\n */\nexport type JSONSchema7Extended = JSONSchema7 & {\n prefixItems?: JSONSchema7[];\n};\n\n/**\n * Checks if a JSON Schema represents a tuple (array with positional items).\n * Supports both draft-07 (items as array) and draft 2020-12 (prefixItems).\n * @param schema - The JSON Schema to check\n * @returns True if the schema represents a tuple\n */\nexport function isJsonSchemaTuple(\n schema: JSONSchema7Extended,\n): schema is JSONSchema7Extended & { type: \"array\" } {\n if (schema.type !== \"array\") {\n return false;\n }\n\n // Draft 2020-12: prefixItems array\n if (schema.prefixItems && Array.isArray(schema.prefixItems)) {\n return true;\n }\n\n // Draft-07: items as array (not object)\n if (Array.isArray(schema.items)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Gets the tuple items from a JSON Schema.\n * Supports both draft-07 (items as array) and draft 2020-12 (prefixItems).\n * @param schema - The JSON Schema tuple\n * @returns Array of item schemas, or undefined if not a tuple\n */\nexport function getJsonSchemaTupleItems(\n schema: JSONSchema7Extended,\n): JSONSchema7[] | undefined {\n if (schema.type !== \"array\") {\n return undefined;\n }\n\n // Draft 2020-12: prefixItems array\n if (schema.prefixItems && Array.isArray(schema.prefixItems)) {\n return schema.prefixItems;\n }\n\n // Draft-07: items as array\n if (Array.isArray(schema.items)) {\n return schema.items as JSONSchema7[];\n }\n\n return undefined;\n}\n\n/**\n * Creates a partial version of a JSON Schema by removing required constraints.\n * This allows LLM to provide only the properties it wants to update.\n * @param schema - The JSON Schema to make partial\n * @returns A new JSON Schema with the required constraint removed\n */\nexport function makeJsonSchemaPartial(schema: JSONSchema7): JSONSchema7 {\n const { required: _required, ...rest } = schema;\n return rest;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=json-schema.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.test.d.ts","sourceRoot":"","sources":["../../src/schema/json-schema.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const json_schema_1 = require("./json-schema");
4
+ describe("looksLikeJSONSchema", () => {
5
+ it("should return true for a valid object schema", () => {
6
+ const schema = {
7
+ type: "object",
8
+ properties: {
9
+ name: { type: "string" },
10
+ },
11
+ };
12
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
13
+ });
14
+ it("should return true for a schema with only properties", () => {
15
+ const schema = {
16
+ properties: {
17
+ name: { type: "string" },
18
+ },
19
+ };
20
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
21
+ });
22
+ it("should return true for a schema with items (array)", () => {
23
+ const schema = {
24
+ type: "array",
25
+ items: { type: "string" },
26
+ };
27
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
28
+ });
29
+ it("should return true for a schema with enum", () => {
30
+ const schema = {
31
+ enum: ["a", "b", "c"],
32
+ };
33
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
34
+ });
35
+ it("should return true for a schema with const", () => {
36
+ const schema = {
37
+ const: "fixed-value",
38
+ };
39
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
40
+ });
41
+ it("should return true for a schema with $ref", () => {
42
+ const schema = {
43
+ $ref: "#/definitions/Person",
44
+ };
45
+ expect((0, json_schema_1.looksLikeJSONSchema)(schema)).toBe(true);
46
+ });
47
+ it("should return false for null", () => {
48
+ expect((0, json_schema_1.looksLikeJSONSchema)(null)).toBe(false);
49
+ });
50
+ it("should return false for non-object", () => {
51
+ expect((0, json_schema_1.looksLikeJSONSchema)("string")).toBe(false);
52
+ expect((0, json_schema_1.looksLikeJSONSchema)(123)).toBe(false);
53
+ expect((0, json_schema_1.looksLikeJSONSchema)(undefined)).toBe(false);
54
+ });
55
+ it("should return false for empty object", () => {
56
+ expect((0, json_schema_1.looksLikeJSONSchema)({})).toBe(false);
57
+ });
58
+ it("should return false for object without schema keys", () => {
59
+ const notSchema = {
60
+ foo: "bar",
61
+ baz: 123,
62
+ };
63
+ expect((0, json_schema_1.looksLikeJSONSchema)(notSchema)).toBe(false);
64
+ });
65
+ });
66
+ describe("isJsonSchemaTuple", () => {
67
+ it("should return true for draft-07 tuple (items as array)", () => {
68
+ const schema = {
69
+ type: "array",
70
+ items: [{ type: "string" }, { type: "number" }],
71
+ };
72
+ expect((0, json_schema_1.isJsonSchemaTuple)(schema)).toBe(true);
73
+ });
74
+ it("should return true for draft 2020-12 tuple (prefixItems)", () => {
75
+ const schema = {
76
+ type: "array",
77
+ prefixItems: [{ type: "string" }, { type: "number" }],
78
+ };
79
+ expect((0, json_schema_1.isJsonSchemaTuple)(schema)).toBe(true);
80
+ });
81
+ it("should return false for regular array schema (items as object)", () => {
82
+ const schema = {
83
+ type: "array",
84
+ items: { type: "string" },
85
+ };
86
+ expect((0, json_schema_1.isJsonSchemaTuple)(schema)).toBe(false);
87
+ });
88
+ it("should return false for non-array schema", () => {
89
+ const schema = {
90
+ type: "object",
91
+ properties: {},
92
+ };
93
+ expect((0, json_schema_1.isJsonSchemaTuple)(schema)).toBe(false);
94
+ });
95
+ it("should return false for array without items or prefixItems", () => {
96
+ const schema = {
97
+ type: "array",
98
+ };
99
+ expect((0, json_schema_1.isJsonSchemaTuple)(schema)).toBe(false);
100
+ });
101
+ });
102
+ describe("getJsonSchemaTupleItems", () => {
103
+ it("should return items for draft-07 tuple", () => {
104
+ const items = [{ type: "string" }, { type: "number" }];
105
+ const schema = {
106
+ type: "array",
107
+ items: items,
108
+ };
109
+ expect((0, json_schema_1.getJsonSchemaTupleItems)(schema)).toEqual(items);
110
+ });
111
+ it("should return prefixItems for draft 2020-12 tuple", () => {
112
+ const prefixItems = [{ type: "string" }, { type: "number" }];
113
+ const schema = {
114
+ type: "array",
115
+ prefixItems: prefixItems,
116
+ };
117
+ expect((0, json_schema_1.getJsonSchemaTupleItems)(schema)).toEqual(prefixItems);
118
+ });
119
+ it("should return undefined for non-array schema", () => {
120
+ const schema = {
121
+ type: "object",
122
+ };
123
+ expect((0, json_schema_1.getJsonSchemaTupleItems)(schema)).toBeUndefined();
124
+ });
125
+ it("should return undefined for array without tuple items", () => {
126
+ const schema = {
127
+ type: "array",
128
+ items: { type: "string" },
129
+ };
130
+ expect((0, json_schema_1.getJsonSchemaTupleItems)(schema)).toBeUndefined();
131
+ });
132
+ it("should prefer prefixItems over items when both present", () => {
133
+ const prefixItems = [{ type: "boolean" }];
134
+ const items = [{ type: "string" }];
135
+ const schema = {
136
+ type: "array",
137
+ prefixItems: prefixItems,
138
+ items: items,
139
+ };
140
+ expect((0, json_schema_1.getJsonSchemaTupleItems)(schema)).toEqual(prefixItems);
141
+ });
142
+ });
143
+ describe("makeJsonSchemaPartial", () => {
144
+ it("should remove required array from schema", () => {
145
+ const schema = {
146
+ type: "object",
147
+ properties: {
148
+ name: { type: "string" },
149
+ age: { type: "number" },
150
+ },
151
+ required: ["name", "age"],
152
+ };
153
+ const partial = (0, json_schema_1.makeJsonSchemaPartial)(schema);
154
+ expect(partial.required).toBeUndefined();
155
+ expect(partial.type).toBe("object");
156
+ expect(partial.properties).toEqual(schema.properties);
157
+ });
158
+ it("should preserve all other properties", () => {
159
+ const schema = {
160
+ type: "object",
161
+ properties: {
162
+ name: { type: "string", description: "The name" },
163
+ },
164
+ required: ["name"],
165
+ additionalProperties: false,
166
+ description: "A person schema",
167
+ title: "Person",
168
+ };
169
+ const partial = (0, json_schema_1.makeJsonSchemaPartial)(schema);
170
+ expect(partial.required).toBeUndefined();
171
+ expect(partial.type).toBe("object");
172
+ expect(partial.properties).toEqual(schema.properties);
173
+ expect(partial.additionalProperties).toBe(false);
174
+ expect(partial.description).toBe("A person schema");
175
+ expect(partial.title).toBe("Person");
176
+ });
177
+ it("should handle schema without required array", () => {
178
+ const schema = {
179
+ type: "object",
180
+ properties: {
181
+ name: { type: "string" },
182
+ },
183
+ };
184
+ const partial = (0, json_schema_1.makeJsonSchemaPartial)(schema);
185
+ expect(partial.required).toBeUndefined();
186
+ expect(partial.type).toBe("object");
187
+ expect(partial.properties).toEqual(schema.properties);
188
+ });
189
+ it("should not mutate the original schema", () => {
190
+ const schema = {
191
+ type: "object",
192
+ properties: {
193
+ name: { type: "string" },
194
+ },
195
+ required: ["name"],
196
+ };
197
+ const partial = (0, json_schema_1.makeJsonSchemaPartial)(schema);
198
+ // Original should be unchanged
199
+ expect(schema.required).toEqual(["name"]);
200
+ // Partial should not have required
201
+ expect(partial.required).toBeUndefined();
202
+ });
203
+ });
204
+ //# sourceMappingURL=json-schema.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.test.js","sourceRoot":"","sources":["../../src/schema/json-schema.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { JSONSchema7 } from \"json-schema\";\nimport {\n getJsonSchemaTupleItems,\n isJsonSchemaTuple,\n JSONSchema7Extended,\n looksLikeJSONSchema,\n makeJsonSchemaPartial,\n} from \"./json-schema\";\n\ndescribe(\"looksLikeJSONSchema\", () => {\n it(\"should return true for a valid object schema\", () => {\n const schema = {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n },\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return true for a schema with only properties\", () => {\n const schema = {\n properties: {\n name: { type: \"string\" },\n },\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return true for a schema with items (array)\", () => {\n const schema = {\n type: \"array\",\n items: { type: \"string\" },\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return true for a schema with enum\", () => {\n const schema = {\n enum: [\"a\", \"b\", \"c\"],\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return true for a schema with const\", () => {\n const schema = {\n const: \"fixed-value\",\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return true for a schema with $ref\", () => {\n const schema = {\n $ref: \"#/definitions/Person\",\n };\n expect(looksLikeJSONSchema(schema)).toBe(true);\n });\n\n it(\"should return false for null\", () => {\n expect(looksLikeJSONSchema(null)).toBe(false);\n });\n\n it(\"should return false for non-object\", () => {\n expect(looksLikeJSONSchema(\"string\")).toBe(false);\n expect(looksLikeJSONSchema(123)).toBe(false);\n expect(looksLikeJSONSchema(undefined)).toBe(false);\n });\n\n it(\"should return false for empty object\", () => {\n expect(looksLikeJSONSchema({})).toBe(false);\n });\n\n it(\"should return false for object without schema keys\", () => {\n const notSchema = {\n foo: \"bar\",\n baz: 123,\n };\n expect(looksLikeJSONSchema(notSchema)).toBe(false);\n });\n});\n\ndescribe(\"isJsonSchemaTuple\", () => {\n it(\"should return true for draft-07 tuple (items as array)\", () => {\n const schema: JSONSchema7Extended = {\n type: \"array\",\n items: [{ type: \"string\" }, { type: \"number\" }],\n };\n expect(isJsonSchemaTuple(schema)).toBe(true);\n });\n\n it(\"should return true for draft 2020-12 tuple (prefixItems)\", () => {\n const schema: JSONSchema7Extended = {\n type: \"array\",\n prefixItems: [{ type: \"string\" }, { type: \"number\" }],\n };\n expect(isJsonSchemaTuple(schema)).toBe(true);\n });\n\n it(\"should return false for regular array schema (items as object)\", () => {\n const schema: JSONSchema7Extended = {\n type: \"array\",\n items: { type: \"string\" },\n };\n expect(isJsonSchemaTuple(schema)).toBe(false);\n });\n\n it(\"should return false for non-array schema\", () => {\n const schema: JSONSchema7Extended = {\n type: \"object\",\n properties: {},\n };\n expect(isJsonSchemaTuple(schema)).toBe(false);\n });\n\n it(\"should return false for array without items or prefixItems\", () => {\n const schema: JSONSchema7Extended = {\n type: \"array\",\n };\n expect(isJsonSchemaTuple(schema)).toBe(false);\n });\n});\n\ndescribe(\"getJsonSchemaTupleItems\", () => {\n it(\"should return items for draft-07 tuple\", () => {\n const items = [{ type: \"string\" }, { type: \"number\" }];\n const schema: JSONSchema7Extended = {\n type: \"array\",\n items: items as JSONSchema7[],\n };\n expect(getJsonSchemaTupleItems(schema)).toEqual(items);\n });\n\n it(\"should return prefixItems for draft 2020-12 tuple\", () => {\n const prefixItems = [{ type: \"string\" }, { type: \"number\" }];\n const schema: JSONSchema7Extended = {\n type: \"array\",\n prefixItems: prefixItems as JSONSchema7[],\n };\n expect(getJsonSchemaTupleItems(schema)).toEqual(prefixItems);\n });\n\n it(\"should return undefined for non-array schema\", () => {\n const schema: JSONSchema7Extended = {\n type: \"object\",\n };\n expect(getJsonSchemaTupleItems(schema)).toBeUndefined();\n });\n\n it(\"should return undefined for array without tuple items\", () => {\n const schema: JSONSchema7Extended = {\n type: \"array\",\n items: { type: \"string\" },\n };\n expect(getJsonSchemaTupleItems(schema)).toBeUndefined();\n });\n\n it(\"should prefer prefixItems over items when both present\", () => {\n const prefixItems = [{ type: \"boolean\" }];\n const items = [{ type: \"string\" }];\n const schema: JSONSchema7Extended = {\n type: \"array\",\n prefixItems: prefixItems as JSONSchema7[],\n items: items as JSONSchema7[],\n };\n expect(getJsonSchemaTupleItems(schema)).toEqual(prefixItems);\n });\n});\n\ndescribe(\"makeJsonSchemaPartial\", () => {\n it(\"should remove required array from schema\", () => {\n const schema: JSONSchema7 = {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n age: { type: \"number\" },\n },\n required: [\"name\", \"age\"],\n };\n\n const partial = makeJsonSchemaPartial(schema);\n\n expect(partial.required).toBeUndefined();\n expect(partial.type).toBe(\"object\");\n expect(partial.properties).toEqual(schema.properties);\n });\n\n it(\"should preserve all other properties\", () => {\n const schema: JSONSchema7 = {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"The name\" },\n },\n required: [\"name\"],\n additionalProperties: false,\n description: \"A person schema\",\n title: \"Person\",\n };\n\n const partial = makeJsonSchemaPartial(schema);\n\n expect(partial.required).toBeUndefined();\n expect(partial.type).toBe(\"object\");\n expect(partial.properties).toEqual(schema.properties);\n expect(partial.additionalProperties).toBe(false);\n expect(partial.description).toBe(\"A person schema\");\n expect(partial.title).toBe(\"Person\");\n });\n\n it(\"should handle schema without required array\", () => {\n const schema: JSONSchema7 = {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n },\n };\n\n const partial = makeJsonSchemaPartial(schema);\n\n expect(partial.required).toBeUndefined();\n expect(partial.type).toBe(\"object\");\n expect(partial.properties).toEqual(schema.properties);\n });\n\n it(\"should not mutate the original schema\", () => {\n const schema: JSONSchema7 = {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n },\n required: [\"name\"],\n };\n\n const partial = makeJsonSchemaPartial(schema);\n\n // Original should be unchanged\n expect(schema.required).toEqual([\"name\"]);\n // Partial should not have required\n expect(partial.required).toBeUndefined();\n });\n});\n"]}
@@ -2,11 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  require("@testing-library/jest-dom");
4
4
  const util_1 = require("util");
5
+ const web_1 = require("stream/web");
5
6
  // Mock Date.now() to return a fixed timestamp for consistent testing
6
7
  const mockDate = new Date(2025, 0, 5, 12, 32, 58, 936);
7
8
  global.Date.now = jest.fn(() => mockDate.getTime());
8
9
  // Add TextEncoder/TextDecoder polyfills for Node.js test environment
9
10
  Object.assign(global, { TextEncoder: util_1.TextEncoder, TextDecoder: util_1.TextDecoder });
11
+ // Add Web Streams API polyfills for jsdom environment (used by @modelcontextprotocol/sdk)
12
+ Object.assign(global, { TransformStream: web_1.TransformStream, ReadableStream: web_1.ReadableStream, WritableStream: web_1.WritableStream });
10
13
  // Mock react-media-recorder for tests (browser APIs not available in Node.js)
11
14
  jest.mock("react-media-recorder", () => ({
12
15
  useReactMediaRecorder: () => ({
@@ -1 +1 @@
1
- {"version":3,"file":"setupTests.js","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":";;AAAA,qCAAmC;AACnC,+BAAgD;AAEhD,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;AAEpD,qEAAqE;AACrE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,WAAW,EAAX,kBAAW,EAAE,WAAW,EAAX,kBAAW,EAAE,CAAC,CAAC;AAEpD,8EAA8E;AAC9E,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,CAAC;IACvC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5B,MAAM,EAAE,MAAM;QACd,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;QACxB,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,IAAI;KACZ,CAAC;CACH,CAAC,CAAC,CAAC","sourcesContent":["import \"@testing-library/jest-dom\";\nimport { TextDecoder, TextEncoder } from \"util\";\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\n// Add TextEncoder/TextDecoder polyfills for Node.js test environment\nObject.assign(global, { TextEncoder, TextDecoder });\n\n// Mock react-media-recorder for tests (browser APIs not available in Node.js)\njest.mock(\"react-media-recorder\", () => ({\n useReactMediaRecorder: () => ({\n status: \"idle\",\n startRecording: jest.fn(),\n stopRecording: jest.fn(),\n mediaBlobUrl: null,\n error: null,\n }),\n}));\n"]}
1
+ {"version":3,"file":"setupTests.js","sourceRoot":"","sources":["../src/setupTests.ts"],"names":[],"mappings":";;AAAA,qCAAmC;AACnC,+BAAgD;AAChD,oCAA6E;AAE7E,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;AAEpD,qEAAqE;AACrE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,WAAW,EAAX,kBAAW,EAAE,WAAW,EAAX,kBAAW,EAAE,CAAC,CAAC;AAEpD,0FAA0F;AAC1F,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,eAAe,EAAf,qBAAe,EAAE,cAAc,EAAd,oBAAc,EAAE,cAAc,EAAd,oBAAc,EAAE,CAAC,CAAC;AAE3E,8EAA8E;AAC9E,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,CAAC;IACvC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5B,MAAM,EAAE,MAAM;QACd,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;QACxB,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,IAAI;KACZ,CAAC;CACH,CAAC,CAAC,CAAC","sourcesContent":["import \"@testing-library/jest-dom\";\nimport { TextDecoder, TextEncoder } from \"util\";\nimport { TransformStream, ReadableStream, WritableStream } from \"stream/web\";\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\n// Add TextEncoder/TextDecoder polyfills for Node.js test environment\nObject.assign(global, { TextEncoder, TextDecoder });\n\n// Add Web Streams API polyfills for jsdom environment (used by @modelcontextprotocol/sdk)\nObject.assign(global, { TransformStream, ReadableStream, WritableStream });\n\n// Mock react-media-recorder for tests (browser APIs not available in Node.js)\njest.mock(\"react-media-recorder\", () => ({\n useReactMediaRecorder: () => ({\n status: \"idle\",\n startRecording: jest.fn(),\n stopRecording: jest.fn(),\n mediaBlobUrl: null,\n error: null,\n }),\n}));\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
1
2
  import type TamboAI from "@tambo-ai/typescript-sdk";
2
3
  import { StagedImage } from "../hooks/use-message-images";
3
4
  /**
@@ -5,7 +6,8 @@ import { StagedImage } from "../hooks/use-message-images";
5
6
  * @param text - The text content, may include \@serverKey:uri resource references
6
7
  * @param images - Array of staged images
7
8
  * @param resourceNames - Map of resource IDs (serverKey:uri) to their display names
9
+ * @param resourceContent - Optional map of prefixed URIs to resolved content (for client-side resources)
8
10
  * @returns Array of message content parts
9
11
  */
10
- export declare function buildMessageContent(text: string, images: StagedImage[], resourceNames?: Record<string, string>): TamboAI.Beta.Threads.ChatCompletionContentPart[];
12
+ export declare function buildMessageContent(text: string, images: StagedImage[], resourceNames?: Record<string, string>, resourceContent?: Map<string, ReadResourceResult>): TamboAI.Beta.Threads.ChatCompletionContentPart[];
11
13
  //# sourceMappingURL=message-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-builder.d.ts","sourceRoot":"","sources":["../../src/util/message-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAsF1D;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,EAAE,EACrB,aAAa,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACzC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,CA4BlD"}
1
+ {"version":3,"file":"message-builder.d.ts","sourceRoot":"","sources":["../../src/util/message-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAwG1D;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,EAAE,EACrB,aAAa,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAC1C,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,EAAE,CA4BlD"}
@@ -25,9 +25,10 @@ const RESOURCE_REFERENCE_PATTERN = /@([a-zA-Z0-9-]+):(\S+)/g;
25
25
  * - The backend routes resources based on the thread's MCP server configuration, not client-side keys
26
26
  * @param text - Text potentially containing resource references
27
27
  * @param resourceNames - Map of full resource IDs (serverKey:uri) to their display names
28
+ * @param resourceContent - Optional map of prefixed URIs to resolved content (for client-side resources)
28
29
  * @returns Array of content parts in order (text and resource parts interleaved)
29
30
  */
30
- function parseResourceReferences(text, resourceNames) {
31
+ function parseResourceReferences(text, resourceNames, resourceContent) {
31
32
  const parts = [];
32
33
  // Use matchAll to avoid global regex state issues
33
34
  const matches = Array.from(text.matchAll(RESOURCE_REFERENCE_PATTERN));
@@ -51,6 +52,21 @@ function parseResourceReferences(text, resourceNames) {
51
52
  if (name) {
52
53
  resource.name = name;
53
54
  }
55
+ // Include resolved content for client-side resources (MCP and registry)
56
+ // Server-side resources won't be in the map - backend resolves them by URI
57
+ const resolvedContent = resourceContent?.get(fullId);
58
+ if (resolvedContent?.contents?.[0]) {
59
+ const content = resolvedContent.contents[0];
60
+ if ("text" in content && content.text) {
61
+ resource.text = content.text;
62
+ }
63
+ else if ("blob" in content && content.blob) {
64
+ resource.blob = content.blob;
65
+ }
66
+ if ("mimeType" in content && content.mimeType) {
67
+ resource.mimeType = content.mimeType;
68
+ }
69
+ }
54
70
  parts.push({ type: "resource", resource });
55
71
  if (match.index !== undefined) {
56
72
  lastIndex = match.index + fullMatch.length;
@@ -77,16 +93,17 @@ function parseResourceReferences(text, resourceNames) {
77
93
  * @param text - The text content, may include \@serverKey:uri resource references
78
94
  * @param images - Array of staged images
79
95
  * @param resourceNames - Map of resource IDs (serverKey:uri) to their display names
96
+ * @param resourceContent - Optional map of prefixed URIs to resolved content (for client-side resources)
80
97
  * @returns Array of message content parts
81
98
  */
82
- function buildMessageContent(text, images, resourceNames = {}) {
99
+ function buildMessageContent(text, images, resourceNames = {}, resourceContent) {
83
100
  const content = [];
84
101
  const hasNonWhitespaceText = text.trim().length > 0;
85
102
  if (hasNonWhitespaceText) {
86
103
  // Parse resource references from the original text so that all
87
104
  // user-visible whitespace (including leading/trailing spaces and
88
105
  // internal spacing) is preserved in the resulting content parts.
89
- const parts = parseResourceReferences(text, resourceNames);
106
+ const parts = parseResourceReferences(text, resourceNames, resourceContent);
90
107
  content.push(...parts);
91
108
  }
92
109
  // Add images at the end
@@ -1 +1 @@
1
- {"version":3,"file":"message-builder.js","sourceRoot":"","sources":["../../src/util/message-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { StagedImage } from \"../hooks/use-message-images\";\n\n/**\n * Regular expression to match MCP resource references in the format: \\@serverKey:uri\n *\n * Examples:\n * - \\@tambo-1hfs429:tambo:test://static/resource/1\n * - \\@linear:file://path/to/file\n *\n * Pattern breakdown:\n * - \\@ - Literal \\@ symbol\n * - ([a-zA-Z0-9-]+) - Server key (alphanumeric + hyphens, client-side routing key)\n * - : - Literal colon separator\n * - (\\S+) - URI (non-whitespace characters, actual resource URI)\n */\nconst RESOURCE_REFERENCE_PATTERN = /@([a-zA-Z0-9-]+):(\\S+)/g;\n\n/**\n * Parses text with resource references and returns interleaved content parts.\n * Resource references have the format: \\@serverKey:uri\n *\n * The serverKey prefix is stripped before sending to the backend because:\n * - It's a client-side routing key (e.g., \"tambo-1hfs429\") used by React SDK to route to the correct MCP connection\n * - The backend only needs the actual resource URI (e.g., \"tambo:test://static/resource/1\")\n * - The backend routes resources based on the thread's MCP server configuration, not client-side keys\n * @param text - Text potentially containing resource references\n * @param resourceNames - Map of full resource IDs (serverKey:uri) to their display names\n * @returns Array of content parts in order (text and resource parts interleaved)\n */\nfunction parseResourceReferences(\n text: string,\n resourceNames: Record<string, string>,\n): TamboAI.Beta.Threads.ChatCompletionContentPart[] {\n const parts: TamboAI.Beta.Threads.ChatCompletionContentPart[] = [];\n\n // Use matchAll to avoid global regex state issues\n const matches = Array.from(text.matchAll(RESOURCE_REFERENCE_PATTERN));\n let lastIndex = 0;\n\n // Find all resource references and interleave with text\n for (const match of matches) {\n const [fullMatch, serverKey, uri] = match;\n const fullId = `${serverKey}:${uri}`;\n\n // Add text before this resource reference (preserve whitespace)\n if (match.index !== undefined && match.index > lastIndex) {\n const textBefore = text.slice(lastIndex, match.index);\n if (textBefore.length > 0) {\n parts.push({\n type: \"text\",\n text: textBefore,\n });\n }\n }\n\n const resource: TamboAI.Resource = { uri };\n const name = resourceNames[fullId];\n if (name) {\n resource.name = name;\n }\n parts.push({ type: \"resource\", resource });\n\n if (match.index !== undefined) {\n lastIndex = match.index + fullMatch.length;\n }\n }\n\n // Add remaining text after the last resource reference (preserve whitespace)\n if (lastIndex < text.length) {\n const textAfter = text.slice(lastIndex);\n if (textAfter.length > 0) {\n parts.push({\n type: \"text\",\n text: textAfter,\n });\n }\n }\n\n // If no resource references were found, return the whole text as a single text part\n if (parts.length === 0 && text.trim()) {\n parts.push({ type: \"text\", text });\n }\n\n return parts;\n}\n\n/**\n * Builds message content with text, MCP resource references, and images\n * @param text - The text content, may include \\@serverKey:uri resource references\n * @param images - Array of staged images\n * @param resourceNames - Map of resource IDs (serverKey:uri) to their display names\n * @returns Array of message content parts\n */\nexport function buildMessageContent(\n text: string,\n images: StagedImage[],\n resourceNames: Record<string, string> = {},\n): TamboAI.Beta.Threads.ChatCompletionContentPart[] {\n const content: TamboAI.Beta.Threads.ChatCompletionContentPart[] = [];\n\n const hasNonWhitespaceText = text.trim().length > 0;\n\n if (hasNonWhitespaceText) {\n // Parse resource references from the original text so that all\n // user-visible whitespace (including leading/trailing spaces and\n // internal spacing) is preserved in the resulting content parts.\n const parts = parseResourceReferences(text, resourceNames);\n content.push(...parts);\n }\n\n // Add images at the end\n for (const image of images) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: image.dataUrl,\n },\n });\n }\n\n if (content.length === 0) {\n throw new Error(\"Message must contain text or images\");\n }\n\n return content;\n}\n"]}
1
+ {"version":3,"file":"message-builder.js","sourceRoot":"","sources":["../../src/util/message-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReadResourceResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type TamboAI from \"@tambo-ai/typescript-sdk\";\nimport { StagedImage } from \"../hooks/use-message-images\";\n\n/**\n * Regular expression to match MCP resource references in the format: \\@serverKey:uri\n *\n * Examples:\n * - \\@tambo-1hfs429:tambo:test://static/resource/1\n * - \\@linear:file://path/to/file\n *\n * Pattern breakdown:\n * - \\@ - Literal \\@ symbol\n * - ([a-zA-Z0-9-]+) - Server key (alphanumeric + hyphens, client-side routing key)\n * - : - Literal colon separator\n * - (\\S+) - URI (non-whitespace characters, actual resource URI)\n */\nconst RESOURCE_REFERENCE_PATTERN = /@([a-zA-Z0-9-]+):(\\S+)/g;\n\n/**\n * Parses text with resource references and returns interleaved content parts.\n * Resource references have the format: \\@serverKey:uri\n *\n * The serverKey prefix is stripped before sending to the backend because:\n * - It's a client-side routing key (e.g., \"tambo-1hfs429\") used by React SDK to route to the correct MCP connection\n * - The backend only needs the actual resource URI (e.g., \"tambo:test://static/resource/1\")\n * - The backend routes resources based on the thread's MCP server configuration, not client-side keys\n * @param text - Text potentially containing resource references\n * @param resourceNames - Map of full resource IDs (serverKey:uri) to their display names\n * @param resourceContent - Optional map of prefixed URIs to resolved content (for client-side resources)\n * @returns Array of content parts in order (text and resource parts interleaved)\n */\nfunction parseResourceReferences(\n text: string,\n resourceNames: Record<string, string>,\n resourceContent?: Map<string, ReadResourceResult>,\n): TamboAI.Beta.Threads.ChatCompletionContentPart[] {\n const parts: TamboAI.Beta.Threads.ChatCompletionContentPart[] = [];\n\n // Use matchAll to avoid global regex state issues\n const matches = Array.from(text.matchAll(RESOURCE_REFERENCE_PATTERN));\n let lastIndex = 0;\n\n // Find all resource references and interleave with text\n for (const match of matches) {\n const [fullMatch, serverKey, uri] = match;\n const fullId = `${serverKey}:${uri}`;\n\n // Add text before this resource reference (preserve whitespace)\n if (match.index !== undefined && match.index > lastIndex) {\n const textBefore = text.slice(lastIndex, match.index);\n if (textBefore.length > 0) {\n parts.push({\n type: \"text\",\n text: textBefore,\n });\n }\n }\n\n const resource: TamboAI.Resource = { uri };\n const name = resourceNames[fullId];\n if (name) {\n resource.name = name;\n }\n\n // Include resolved content for client-side resources (MCP and registry)\n // Server-side resources won't be in the map - backend resolves them by URI\n const resolvedContent = resourceContent?.get(fullId);\n if (resolvedContent?.contents?.[0]) {\n const content = resolvedContent.contents[0];\n if (\"text\" in content && content.text) {\n resource.text = content.text;\n } else if (\"blob\" in content && content.blob) {\n resource.blob = content.blob;\n }\n if (\"mimeType\" in content && content.mimeType) {\n resource.mimeType = content.mimeType;\n }\n }\n\n parts.push({ type: \"resource\", resource });\n\n if (match.index !== undefined) {\n lastIndex = match.index + fullMatch.length;\n }\n }\n\n // Add remaining text after the last resource reference (preserve whitespace)\n if (lastIndex < text.length) {\n const textAfter = text.slice(lastIndex);\n if (textAfter.length > 0) {\n parts.push({\n type: \"text\",\n text: textAfter,\n });\n }\n }\n\n // If no resource references were found, return the whole text as a single text part\n if (parts.length === 0 && text.trim()) {\n parts.push({ type: \"text\", text });\n }\n\n return parts;\n}\n\n/**\n * Builds message content with text, MCP resource references, and images\n * @param text - The text content, may include \\@serverKey:uri resource references\n * @param images - Array of staged images\n * @param resourceNames - Map of resource IDs (serverKey:uri) to their display names\n * @param resourceContent - Optional map of prefixed URIs to resolved content (for client-side resources)\n * @returns Array of message content parts\n */\nexport function buildMessageContent(\n text: string,\n images: StagedImage[],\n resourceNames: Record<string, string> = {},\n resourceContent?: Map<string, ReadResourceResult>,\n): TamboAI.Beta.Threads.ChatCompletionContentPart[] {\n const content: TamboAI.Beta.Threads.ChatCompletionContentPart[] = [];\n\n const hasNonWhitespaceText = text.trim().length > 0;\n\n if (hasNonWhitespaceText) {\n // Parse resource references from the original text so that all\n // user-visible whitespace (including leading/trailing spaces and\n // internal spacing) is preserved in the resulting content parts.\n const parts = parseResourceReferences(text, resourceNames, resourceContent);\n content.push(...parts);\n }\n\n // Add images at the end\n for (const image of images) {\n content.push({\n type: \"image_url\",\n image_url: {\n url: image.dataUrl,\n },\n });\n }\n\n if (content.length === 0) {\n throw new Error(\"Message must contain text or images\");\n }\n\n return content;\n}\n"]}