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==