diff --git a/apps/app/package.json b/apps/app/package.json index 7418f4855e..297a0145b1 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -13,6 +13,7 @@ "dependencies": { "@ai-sdk/openai": "^1.1.12", "@ai-sdk/provider": "^1.0.7", + "@ai-sdk/react": "^1.1.21", "@aws-sdk/client-s3": "^3.758.0", "@aws-sdk/s3-request-presigner": "^3.758.0", "@browserbasehq/sdk": "^2.3.0", @@ -37,7 +38,7 @@ "@types/d3": "^7.4.3", "@uploadthing/react": "^7.2.0", "@upstash/ratelimit": "^2.0.5", - "ai": "^4.1.41", + "ai": "^4.1.54", "argon2": "^0.41.1", "bun": "^1.2.2", "crypto": "^1.0.1", @@ -79,6 +80,7 @@ "uploadthing": "^7.5.0", "use-debounce": "^10.0.4", "use-long-press": "^3.2.0", + "uuid": "^11.1.0", "xml2js": "^0.6.2", "yarn": "^1.22.22", "zustand": "^5.0.3" @@ -89,6 +91,7 @@ "@types/node": "^22.13.2", "@types/react": "19.0.10", "@types/react-dom": "19.0.4", + "@types/uuid": "^10.0.0", "postcss": "^8.5.2", "tailwindcss": "^3.4.17", "typescript": "^5.7.3" diff --git a/apps/app/src/app/[locale]/layout.tsx b/apps/app/src/app/[locale]/layout.tsx index 27d1e2041f..efa6c12178 100644 --- a/apps/app/src/app/[locale]/layout.tsx +++ b/apps/app/src/app/[locale]/layout.tsx @@ -10,103 +10,106 @@ import localFont from "next/font/local"; import { NuqsAdapter } from "nuqs/adapters/next/app"; import { Toaster } from "sonner"; import { Providers } from "./providers"; +import { ChatProvider } from "@/components/chat/ChatProvider"; export const metadata: Metadata = { - metadataBase: new URL("https://app.trycomp.ai"), - title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - twitter: { - title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - images: [ - { - url: "https://cdn.trycomp.ai/opengraph-image.jpg", - width: 800, - height: 600, - }, - { - url: "https://cdn.trycomp.ai/opengraph-image.jpg", - width: 1800, - height: 1600, - }, - ], - }, - openGraph: { - title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", - url: "https://app.trycomp.ai", - siteName: "Comp AI", - images: [ - { - url: "https://cdn.trycomp.ai/opengraph-image.jpg", - width: 800, - height: 600, - }, - { - url: "https://cdn.trycomp.ai/opengraph-image.jpg", - width: 1800, - height: 1600, - }, - ], - locale: "en_US", - type: "website", - }, + metadataBase: new URL("https://app.trycomp.ai"), + title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + twitter: { + title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + images: [ + { + url: "https://cdn.trycomp.ai/opengraph-image.jpg", + width: 800, + height: 600, + }, + { + url: "https://cdn.trycomp.ai/opengraph-image.jpg", + width: 1800, + height: 1600, + }, + ], + }, + openGraph: { + title: "Comp AI | Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + description: "Automate SOC 2, ISO 27001 and GDPR compliance with AI.", + url: "https://app.trycomp.ai", + siteName: "Comp AI", + images: [ + { + url: "https://cdn.trycomp.ai/opengraph-image.jpg", + width: 800, + height: 600, + }, + { + url: "https://cdn.trycomp.ai/opengraph-image.jpg", + width: 1800, + height: 1600, + }, + ], + locale: "en_US", + type: "website", + }, }; export const viewport = { - width: "device-width", - initialScale: 1, - maximumScale: 1, - userScalable: false, - themeColor: [ - { media: "(prefers-color-scheme: light)" }, - { media: "(prefers-color-scheme: dark)" }, - ], + width: "device-width", + initialScale: 1, + maximumScale: 1, + userScalable: false, + themeColor: [ + { media: "(prefers-color-scheme: light)" }, + { media: "(prefers-color-scheme: dark)" }, + ], }; const font = localFont({ - src: "/../../../public/fonts/GeneralSans-Variable.ttf", - display: "swap", - variable: "--font-general-sans", + src: "/../../../public/fonts/GeneralSans-Variable.ttf", + display: "swap", + variable: "--font-general-sans", }); export const preferredRegion = ["auto"]; export const maxDuration = 5; if (env.NEXT_PUBLIC_POSTHOG_KEY && env.NEXT_PUBLIC_POSTHOG_HOST) { - initializeServer({ - apiKey: env.NEXT_PUBLIC_POSTHOG_KEY, - apiHost: env.NEXT_PUBLIC_POSTHOG_HOST, - }); + initializeServer({ + apiKey: env.NEXT_PUBLIC_POSTHOG_KEY, + apiHost: env.NEXT_PUBLIC_POSTHOG_HOST, + }); } export default async function Layout(props: { - children: React.ReactNode; - params: Promise<{ locale: string }>; + children: React.ReactNode; + params: Promise<{ locale: string }>; }) { - const params = await props.params; + const params = await props.params; - const { locale } = params; + const { locale } = params; - const { children } = props; + const { children } = props; - return ( - - - - - -
{children}
-
-
-
- - - - ); + return ( + + + + + + +
{children}
+
+
+
+
+ + + + ); } diff --git a/apps/app/src/app/api/chat/route.ts b/apps/app/src/app/api/chat/route.ts index 8419ab0b0b..a736dc1e6d 100644 --- a/apps/app/src/app/api/chat/route.ts +++ b/apps/app/src/app/api/chat/route.ts @@ -1,5 +1,6 @@ import { openai } from "@ai-sdk/openai"; -import { convertToCoreMessages, streamText } from "ai"; +import { streamText } from "ai"; +import { env } from "@/env.mjs"; export const runtime = "nodejs"; export const maxDuration = 30; @@ -7,12 +8,29 @@ export const maxDuration = 30; export async function POST(req: Request) { const { messages } = await req.json(); - const result = await streamText({ - model: openai("gpt-4o-mini"), - system: - "You generate markdown documents for users. Unless specified, this is a draft. Keep things shortish. Do not add any supplementary text, as everything you say will be placed into a document. If you're confused however, it's okay to ask a user for info. Responses must be either a chat response, or a document. Don't add bold styling to headings.", - messages: convertToCoreMessages(messages), - }); + if (!env.OPENAI_API_KEY) { + return new Response( + JSON.stringify({ error: "OpenAI API key is not configured" }), + { status: 500 } + ); + } - return result.toDataStreamResponse(); + try { + const result = await streamText({ + model: openai("gpt-4o-mini"), + system: + "You are a helpful assistant. Provide concise, accurate, and helpful responses to user queries.", + messages, + }); + + return result.toDataStreamResponse(); + } catch (error) { + console.error("Error in chat API:", error); + return new Response( + JSON.stringify({ + error: "An error occurred while processing your request", + }), + { status: 500 } + ); + } } diff --git a/apps/app/src/components/chat/ChatButton.tsx b/apps/app/src/components/chat/ChatButton.tsx new file mode 100644 index 0000000000..2023ca572e --- /dev/null +++ b/apps/app/src/components/chat/ChatButton.tsx @@ -0,0 +1,34 @@ +"use client"; + +import { useState } from "react"; +import { ChatBubbleIcon } from "@radix-ui/react-icons"; +import { ChatInterface } from "./ChatInterface"; +import { Button } from "@bubba/ui/button"; +import { cn } from "@bubba/ui/cn"; + +interface ChatButtonProps { + className?: string; +} + +export function ChatButton({ className }: ChatButtonProps) { + const [isOpen, setIsOpen] = useState(false); + + const toggleChat = () => { + setIsOpen(!isOpen); + }; + + return ( +
+ {isOpen && setIsOpen(false)} />} + +
+ ); +} diff --git a/apps/app/src/components/chat/ChatInterface.tsx b/apps/app/src/components/chat/ChatInterface.tsx new file mode 100644 index 0000000000..92d93f9be9 --- /dev/null +++ b/apps/app/src/components/chat/ChatInterface.tsx @@ -0,0 +1,151 @@ +"use client"; + +import { useChat } from "@/hooks/chat/useChat"; +import type { ChatMessage } from "@/hooks/chat/useChat"; +import { useRef, useEffect } from "react"; +import { Cross2Icon, PaperPlaneIcon, PersonIcon } from "@radix-ui/react-icons"; +import { Button } from "@bubba/ui/button"; +import { Input } from "@bubba/ui/input"; +import { Card, CardContent, CardHeader, CardTitle } from "@bubba/ui/card"; +import { cn } from "@bubba/ui/cn"; +import { Avatar, AvatarFallback, AvatarImage } from "@bubba/ui/avatar"; + +interface ChatInterfaceProps { + onClose: () => void; +} + +export function ChatInterface({ onClose }: ChatInterfaceProps) { + const { messages, input, handleInputChange, handleSubmit, isLoading } = + useChat(); + const messagesEndRef = useRef(null); + + // Scroll to bottom when messages change + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + }, [messages]); + + // Helper to determine if a specific message is currently being generated + const isGeneratingMessage = (message: ChatMessage, index: number) => { + return ( + isLoading && + index === messages.length - 1 && + message.role === "assistant" && + message.content === "" + ); + }; + + // Format timestamp + const formatTime = () => { + const now = new Date(); + return now.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }); + }; + + return ( + + +
+ Chat Assistant + +
+
+ + + {messages.length === 0 ? ( +
+

How can I help you today?

+
+ ) : ( + messages.map((message: ChatMessage, index) => ( +
+
+ {message.role === "user" ? ( + + + U + + + ) : ( + + + AI + + + )} + +
+
+ + {message.role === "user" ? "User" : "Assistant"} + + + {formatTime()} + +
+ + {isGeneratingMessage(message, index) ? ( +
+
+
+
+
+
+ + Generating response... + +
+ ) : ( +

+ {message.content} +

+ )} +
+
+
+ )) + )} +
+ + +
+
+ + +
+
+ + ); +} diff --git a/apps/app/src/components/chat/ChatProvider.tsx b/apps/app/src/components/chat/ChatProvider.tsx new file mode 100644 index 0000000000..bb4d2eda7e --- /dev/null +++ b/apps/app/src/components/chat/ChatProvider.tsx @@ -0,0 +1,17 @@ +"use client"; + +import type { ReactNode } from "react"; +import { ChatButton } from "./ChatButton"; + +interface ChatProviderProps { + children: ReactNode; +} + +export function ChatProvider({ children }: ChatProviderProps) { + return ( + <> + {children} + + + ); +} diff --git a/apps/app/src/hooks/chat/useChat.ts b/apps/app/src/hooks/chat/useChat.ts new file mode 100644 index 0000000000..a7821cdbc9 --- /dev/null +++ b/apps/app/src/hooks/chat/useChat.ts @@ -0,0 +1,37 @@ +"use client"; + +import { useChat as useAIChat } from "@ai-sdk/react"; +import { v4 as uuid } from "uuid"; + +export interface ChatMessage { + id: string; + role: "user" | "assistant"; + content: string; +} + +export function useChat() { + const { + messages: aiMessages, + input, + handleInputChange, + handleSubmit, + isLoading, + } = useAIChat({ + api: "/api/chat", + }); + + // Convert AI SDK messages to our ChatMessage format + const messages: ChatMessage[] = aiMessages.map((msg) => ({ + id: msg.id || uuid(), + role: msg.role as "user" | "assistant", + content: msg.content, + })); + + return { + messages, + input, + handleInputChange, + handleSubmit, + isLoading, + }; +} diff --git a/bun.lock b/bun.lock index f66176a54b..e63f976ecd 100644 --- a/bun.lock +++ b/bun.lock @@ -30,6 +30,7 @@ "dependencies": { "@ai-sdk/openai": "^1.1.12", "@ai-sdk/provider": "^1.0.7", + "@ai-sdk/react": "^1.1.21", "@aws-sdk/client-s3": "^3.758.0", "@aws-sdk/s3-request-presigner": "^3.758.0", "@browserbasehq/sdk": "^2.3.0", @@ -54,7 +55,7 @@ "@types/d3": "^7.4.3", "@uploadthing/react": "^7.2.0", "@upstash/ratelimit": "^2.0.5", - "ai": "^4.1.41", + "ai": "^4.1.54", "argon2": "^0.41.1", "bun": "^1.2.2", "crypto": "^1.0.1", @@ -96,6 +97,7 @@ "uploadthing": "^7.5.0", "use-debounce": "^10.0.4", "use-long-press": "^3.2.0", + "uuid": "^11.1.0", "xml2js": "^0.6.2", "yarn": "^1.22.22", "zustand": "^5.0.3", @@ -106,6 +108,7 @@ "@types/node": "^22.13.2", "@types/react": "19.0.10", "@types/react-dom": "19.0.4", + "@types/uuid": "^10.0.0", "postcss": "^8.5.2", "tailwindcss": "^3.4.17", "typescript": "^5.7.3", @@ -333,7 +336,7 @@ "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@1.0.22", "", { "dependencies": { "@ai-sdk/provider": "0.0.26", "eventsource-parser": "^1.1.2", "nanoid": "^3.3.7", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ=="], - "@ai-sdk/react": ["@ai-sdk/react@0.0.70", "", { "dependencies": { "@ai-sdk/provider-utils": "1.0.22", "@ai-sdk/ui-utils": "0.0.50", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.0.0" }, "optionalPeers": ["react", "zod"] }, "sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ=="], + "@ai-sdk/react": ["@ai-sdk/react@1.1.21", "", { "dependencies": { "@ai-sdk/provider-utils": "2.1.11", "@ai-sdk/ui-utils": "1.1.17", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.0.0" }, "optionalPeers": ["react", "zod"] }, "sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg=="], "@ai-sdk/solid": ["@ai-sdk/solid@0.0.54", "", { "dependencies": { "@ai-sdk/provider-utils": "1.0.22", "@ai-sdk/ui-utils": "0.0.50" }, "peerDependencies": { "solid-js": "^1.7.7" }, "optionalPeers": ["solid-js"] }, "sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ=="], @@ -1471,6 +1474,8 @@ "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], + "@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], + "@types/ws": ["@types/ws@7.4.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww=="], "@types/xml2js": ["@types/xml2js@0.4.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ=="], @@ -3539,6 +3544,10 @@ "@ai-sdk/provider-utils/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], + "@ai-sdk/react/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.1.11", "", { "dependencies": { "@ai-sdk/provider": "1.0.10", "eventsource-parser": "^3.0.0", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-lMnXA5KaRJidzW7gQmlo/SnX6D+AKk5GxHFcQtOaGOSJNmu/qcNZc1rGaO7K5qW52OvCLXtnWudR4cc/FvMpVQ=="], + + "@ai-sdk/react/@ai-sdk/ui-utils": ["@ai-sdk/ui-utils@1.1.17", "", { "dependencies": { "@ai-sdk/provider": "1.0.10", "@ai-sdk/provider-utils": "2.1.11", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-fCnp/wntZGqPf6tiCmhuQoSDLSBhXoI5DU2JX4As96EO870+jliE6ozvYUwYOZC6Ta2OKAjjWPcSP7HeHX0b+g=="], + "@ai-sdk/ui-utils/@ai-sdk/provider": ["@ai-sdk/provider@0.0.26", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg=="], "@asamuzakjp/css-color/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -3641,6 +3650,8 @@ "ai/@ai-sdk/provider": ["@ai-sdk/provider@0.0.26", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg=="], + "ai/@ai-sdk/react": ["@ai-sdk/react@0.0.70", "", { "dependencies": { "@ai-sdk/provider-utils": "1.0.22", "@ai-sdk/ui-utils": "0.0.50", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.0.0" }, "optionalPeers": ["react", "zod"] }, "sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ=="], + "ansi-escapes/type-fest": ["type-fest@1.4.0", "", {}, "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA=="], "are-we-there-yet/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], @@ -3865,6 +3876,10 @@ "@ai-sdk/openai/@ai-sdk/provider-utils/nanoid": ["nanoid@3.3.6", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="], + "@ai-sdk/react/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.0", "", {}, "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA=="], + + "@ai-sdk/react/@ai-sdk/provider-utils/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], @@ -3945,8 +3960,6 @@ "comp.ai/ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.1.11", "", { "dependencies": { "@ai-sdk/provider": "1.0.10", "eventsource-parser": "^3.0.0", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-lMnXA5KaRJidzW7gQmlo/SnX6D+AKk5GxHFcQtOaGOSJNmu/qcNZc1rGaO7K5qW52OvCLXtnWudR4cc/FvMpVQ=="], - "comp.ai/ai/@ai-sdk/react": ["@ai-sdk/react@1.1.21", "", { "dependencies": { "@ai-sdk/provider-utils": "2.1.11", "@ai-sdk/ui-utils": "1.1.17", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "zod": "^3.0.0" }, "optionalPeers": ["react", "zod"] }, "sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg=="], - "comp.ai/ai/@ai-sdk/ui-utils": ["@ai-sdk/ui-utils@1.1.17", "", { "dependencies": { "@ai-sdk/provider": "1.0.10", "@ai-sdk/provider-utils": "2.1.11", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-fCnp/wntZGqPf6tiCmhuQoSDLSBhXoI5DU2JX4As96EO870+jliE6ozvYUwYOZC6Ta2OKAjjWPcSP7HeHX0b+g=="], "data-urls/whatwg-url/tr46": ["tr46@5.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g=="], diff --git a/yarn.lock b/yarn.lock index b30dba40f1..9b4b6d600d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,7 +80,7 @@ swr "^2.2.5" throttleit "2.1.0" -"@ai-sdk/react@1.1.21": +"@ai-sdk/react@1.1.21", "@ai-sdk/react@^1.1.21": version "1.1.21" resolved "https://registry.npmjs.org/@ai-sdk/react/-/react-1.1.21.tgz" integrity sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg== @@ -1053,7 +1053,6 @@ resolved "workspace:packages/db" devDependencies: "@bubba/tsconfig" "workspace:*" - devDependencies: typescript "^5.7.3" dependencies: "@auth/prisma-adapter" "^2.7.4" @@ -5300,6 +5299,11 @@ resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz" integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== +"@types/uuid@^10.0.0": + version "10.0.0" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz" + integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== + "@types/ws@^7.4.7": version "7.4.7" resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" @@ -5525,7 +5529,7 @@ ai@3.4.33, ai@^3.4.33: secure-json-parse "^2.7.0" zod-to-json-schema "^3.23.3" -ai@^4.1.41: +ai@^4.1.54: version "4.1.54" resolved "https://registry.npmjs.org/ai/-/ai-4.1.54.tgz" integrity sha512-VcUZhNEC9i1OpdhDaz1cF0IllgMqhwoUdqHQT1U3dKvS9KnOa9qvEtUUAilA+VHI/1LSZF4VzGhXPC7QMT9NMg== @@ -6301,23 +6305,22 @@ commander@11.1.0: resolved "workspace:apps/app" devDependencies: "@bubba/db" "workspace:*" - devDependencies: "@trigger.dev/build" "3.3.17" "@types/node" "^22.13.2" "@types/react" "19.0.10" "@types/react-dom" "19.0.4" + "@types/uuid" "^10.0.0" postcss "^8.5.2" tailwindcss "^3.4.17" typescript "^5.7.3" dependencies: "@ai-sdk/openai" "^1.1.12" "@ai-sdk/provider" "^1.0.7" + "@ai-sdk/react" "^1.1.21" "@aws-sdk/client-s3" "^3.758.0" "@aws-sdk/s3-request-presigner" "^3.758.0" "@browserbasehq/sdk" "^2.3.0" - dependencies: "@bubba/notifications" "workspace:*" - dependencies: "@date-fns/tz" "^1.2.0" "@hookform/resolvers" "^3.10.0" "@nangohq/frontend" "^0.53.1" @@ -6338,7 +6341,7 @@ commander@11.1.0: "@types/d3" "^7.4.3" "@uploadthing/react" "^7.2.0" "@upstash/ratelimit" "^2.0.5" - ai "^4.1.41" + ai "^4.1.54" argon2 "^0.41.1" bun "^1.2.2" crypto "^1.0.1" @@ -6380,6 +6383,7 @@ commander@11.1.0: uploadthing "^7.5.0" use-debounce "^10.0.4" use-long-press "^3.2.0" + uuid "^11.1.0" xml2js "^0.6.2" yarn "^1.22.22" zustand "^5.0.3" @@ -13353,7 +13357,7 @@ uuid@^9.0.0, uuid@^9.0.1: resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== -uuid@^11.0.5: +uuid@^11.0.5, uuid@^11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz" integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==