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;
}