diff --git a/components/VercelChat/tools/CreateArtistToolResult.tsx b/components/VercelChat/tools/CreateArtistToolResult.tsx index cd891790d..2128fc3ee 100644 --- a/components/VercelChat/tools/CreateArtistToolResult.tsx +++ b/components/VercelChat/tools/CreateArtistToolResult.tsx @@ -1,6 +1,5 @@ import React, { useEffect } from "react"; import { CreateArtistResult } from "@/types/createArtistResult"; -import useCreateArtistTool from "@/hooks/useCreateArtistTool"; import GenericSuccess from "./GenericSuccess"; import { useArtistProvider } from "@/providers/ArtistProvider"; @@ -19,7 +18,6 @@ export function CreateArtistToolResult({ result, }: CreateArtistToolResultProps) { const { getArtists } = useArtistProvider(); - const { isProcessing, error: processingError } = useCreateArtistTool(result); useEffect(() => { getArtists(result.artistAccountId); @@ -46,13 +44,7 @@ export function CreateArtistToolResult({ ); } diff --git a/hooks/useCreateArtistTool.ts b/hooks/useCreateArtistTool.ts deleted file mode 100644 index a5263662e..000000000 --- a/hooks/useCreateArtistTool.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { useEffect, useState } from "react"; -import { useVercelChatContext } from "@/providers/VercelChatProvider"; -import { useConversationsProvider } from "@/providers/ConversationsProvider"; -import { CreateArtistResult } from "@/types/createArtistResult"; -import copyMessages from "@/lib/messages/copyMessages"; -import { usePrivy } from "@privy-io/react-auth"; - -/** - * Hook for managing the create artist tool result - * Handles refreshing artists, copying messages, and navigation - */ -export function useCreateArtistTool(result: CreateArtistResult) { - const { status, id } = useVercelChatContext(); - const { refetchConversations } = useConversationsProvider(); - const { getAccessToken } = usePrivy(); - const [isProcessing, setIsProcessing] = useState(false); - const [isSuccess, setIsSuccess] = useState(false); - const [error, setError] = useState(null); - - useEffect(() => { - // Only process when streaming is finished - const isFinishedStreaming = status === "ready"; - - // Skip if no artist data or already processing - const shouldSkip = - !result.artist || - !result.artist.account_id || - isProcessing || - !isFinishedStreaming; - if (shouldSkip) { - return; - } - - const processCreateArtistResult = async () => { - try { - setIsProcessing(true); - - const accessToken = await getAccessToken(); - if (!accessToken) return; - - // Step 1: Check if we need to copy messages and redirect - const needsRedirect = id !== result.newRoomId && !!result.newRoomId; - - if (needsRedirect) { - // Copy messages from current room to the newly created room - const success = await copyMessages( - id as string, - result.newRoomId as string, - accessToken, - ); - - // Refresh conversations to show the new chat - await refetchConversations(); - - if (success) { - // Update the URL to point to the new conversation - window.history.replaceState({}, "", `/chat/${result.newRoomId}`); - setIsSuccess(true); - } else { - console.error("Failed to copy messages"); - setError("Failed to copy messages to the new artist"); - } - } else { - setIsSuccess(true); - } - } catch (error) { - console.error("Error in useCreateArtistTool:", error); - setError(error instanceof Error ? error.message : "Unknown error"); - } finally { - setIsProcessing(false); - } - }; - - processCreateArtistResult(); - }, [ - status, - result, - id, - isProcessing, - refetchConversations, - getAccessToken, - ]); - - return { - isProcessing, - isSuccess, - error, - }; -} - -export default useCreateArtistTool; diff --git a/hooks/useVercelChat.ts b/hooks/useVercelChat.ts index 5990ba669..24ff3fb42 100644 --- a/hooks/useVercelChat.ts +++ b/hooks/useVercelChat.ts @@ -21,6 +21,7 @@ import { usePrivy } from "@privy-io/react-auth"; import { TextAttachment } from "@/types/textAttachment"; import { formatTextAttachments } from "@/lib/chat/formatTextAttachments"; import { useDeleteTrailingMessages } from "./useDeleteTrailingMessages"; +import { z } from "zod"; // 30 days in seconds for Supabase signed URL expiry const SIGNED_URL_EXPIRES_SECONDS = 60 * 60 * 24 * 30; @@ -61,6 +62,7 @@ export function useVercelChat({ const { refetchCredits } = usePaymentProvider(); const { transport, getHeaders } = useChatTransport(); const { authenticated } = usePrivy(); + const redirectPathRef = useRef(null); // Load artist files for mentions (from Supabase) const { files: allArtistFiles = [] } = useArtistFilesForMentions(); @@ -180,13 +182,28 @@ export function useVercelChat({ transport, experimental_throttle: 100, generateId: generateUUID, + dataPartSchemas: { + redirect: z.object({ path: z.string() }), + }, onError: (e) => { + redirectPathRef.current = null; console.error("An error occurred, please try again!", e); toast.error("An error occurred, please try again!"); }, + onData: (part) => { + if (part.type === "data-redirect" && part.data.path.startsWith("/")) { + redirectPathRef.current = part.data.path; + } + }, onFinish: async () => { // Update credits after AI response completes await refetchCredits(); + + if (redirectPathRef.current) { + const redirectPath = redirectPathRef.current; + redirectPathRef.current = null; + window.history.replaceState({}, "", redirectPath); + } }, }); diff --git a/lib/messages/copyMessages.ts b/lib/messages/copyMessages.ts deleted file mode 100644 index 541d4ec85..000000000 --- a/lib/messages/copyMessages.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { getClientApiBaseUrl } from "@/lib/api/getClientApiBaseUrl"; -import type { - CopyChatMessagesRequest, - CopyChatMessagesResponse, -} from "@/types/chatMessages"; - -/** - * Client function to copy messages between rooms - * @param sourceRoomId ID of the source room to copy messages from - * @param targetRoomId ID of the target room to copy messages to - * @returns Promise resolving to a boolean indicating success - */ -export async function copyMessages( - sourceRoomId: string, - targetRoomId: string, - accessToken: string, -): Promise { - try { - const url = getClientApiBaseUrl(); - const payload: CopyChatMessagesRequest = { - targetChatId: targetRoomId, - clearExisting: true, - }; - - const response = await fetch( - `${url}/api/chats/${encodeURIComponent(sourceRoomId)}/messages/copy`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${accessToken}`, - }, - body: JSON.stringify(payload), - }, - ); - - const result = (await response.json().catch(() => null)) as - | CopyChatMessagesResponse - | null; - - const isSuccess = response.ok && result?.status === "success"; - if (!isSuccess) { - const missingFields = result?.missing_fields?.join(", "); - const details = missingFields - ? `${result?.error || result?.message || "Request validation failed"} (missing_fields: ${missingFields})` - : result?.error || result?.message || `HTTP ${response.status}`; - console.error("Failed to copy messages:", details); - return false; - } - - return true; - } catch (error) { - console.error("Error copying messages:", error); - return false; - } -} - -export default copyMessages; diff --git a/types/createArtistResult.ts b/types/createArtistResult.ts index b8be6de59..f1e527991 100644 --- a/types/createArtistResult.ts +++ b/types/createArtistResult.ts @@ -7,5 +7,4 @@ export interface CreateArtistResult { artistAccountId?: string; message: string; error?: string; - newRoomId?: string | null; }