diff --git a/Makefile b/Makefile index b5fd1806..067f6920 100644 --- a/Makefile +++ b/Makefile @@ -279,7 +279,7 @@ docker-publish: @echo "==========================================" @IMAGE=registry.xueai.art/deerflow/deerflow-$(SVC):$(VER); \ DOCKERFILE=$$(case "$(SVC)" in \ - frontend) echo "frontend/Dockerfile.prod";; \ + frontend) echo "frontend/Dockerfile";; \ gateway) echo "backend/Dockerfile";; \ langgraph) echo "backend/Dockerfile";; \ *) echo "";; \ @@ -302,4 +302,4 @@ docker-publish: exit 1; \ fi; \ echo "✓ Docker image $$IMAGE built and pushed successfully"; \ - fi \ No newline at end of file + fi diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx index 11d45830..b97a586b 100644 --- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx +++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx @@ -1,6 +1,7 @@ "use client"; import { FilesIcon, ListTodoIcon, XIcon } from "lucide-react"; +import { useSearchParams } from "next/navigation"; import { useCallback, useEffect, useMemo, useState } from "react"; import { ConversationEmptyState } from "@/components/ai-elements/conversation"; @@ -54,6 +55,20 @@ export default function ChatPage() { fullscreen, } = useArtifacts(); const { threadId, isNewThread, setIsNewThread, isMock } = useThreadChat(); + const searchParams = useSearchParams(); + + // Submission strategy is controlled by `isnew` query param only. + // - isnew=false: reuse existing thread + // - otherwise: create/start a new session + const createNewSession = useMemo(() => { + if (!isNewThread) { + return false; + } + return searchParams.get("isnew")?.trim().toLowerCase() !== "false"; + }, [isNewThread, searchParams]); + const streamThreadId = useMemo(() => { + return isNewThread && createNewSession ? undefined : threadId; + }, [createNewSession, isNewThread, threadId]); const { showNotification } = useNotification(); @@ -64,7 +79,7 @@ export default function ChatPage() { isBootstrapping: isSelectedSkillBootstrapping, } = useSelectedSkillListener({ threadId }); const [thread, sendMessage, isUploading] = useThreadStream({ - threadId: isNewThread ? undefined : threadId, + threadId: streamThreadId, context: settings.context, isMock, onStart: (currentThreadId) => { diff --git a/frontend/src/components/workspace/chats/use-thread-chat.ts b/frontend/src/components/workspace/chats/use-thread-chat.ts index b3164485..f81c93a7 100644 --- a/frontend/src/components/workspace/chats/use-thread-chat.ts +++ b/frontend/src/components/workspace/chats/use-thread-chat.ts @@ -11,7 +11,14 @@ export function useThreadChat() { const searchParams = useSearchParams(); const [threadId, setThreadId] = useState(() => { - return threadIdFromPath === "new" ? uuid() : threadIdFromPath; + if (threadIdFromPath === "new") { + const shouldUseQueryThreadId = pathname.startsWith("/workspace/chats/"); + const queryThreadId = shouldUseQueryThreadId + ? searchParams.get("thread_id")?.trim() + : undefined; + return queryThreadId ?? uuid(); + } + return threadIdFromPath; }); const [isNewThread, setIsNewThread] = useState( @@ -21,9 +28,16 @@ export function useThreadChat() { useEffect(() => { if (pathname.endsWith("/new")) { setIsNewThread(true); - setThreadId(uuid()); + const shouldUseQueryThreadId = pathname.startsWith("/workspace/chats/"); + const queryThreadId = shouldUseQueryThreadId + ? searchParams.get("thread_id")?.trim() + : undefined; + setThreadId(queryThreadId ?? uuid()); + return; } - }, [pathname]); + setIsNewThread(false); + setThreadId(threadIdFromPath); + }, [pathname, searchParams, threadIdFromPath]); const isMock = searchParams.get("mock") === "true"; return { threadId, isNewThread, setIsNewThread, isMock }; }