From f67aa274344673fd753b159c4429c2fdf8a47979 Mon Sep 17 00:00:00 2001 From: Titan Date: Thu, 19 Mar 2026 19:15:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=AD=89=E5=BE=85=20thread=20=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=8F=AF=E8=AF=BB=E4=BB=A5=E9=81=BF=E5=85=8D=E8=BF=87?= =?UTF-8?q?=E6=97=A9=E5=B1=95=E7=A4=BAchat=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 22 ++++---- .../app/workspace/chats/[thread_id]/page.tsx | 52 +++++++++++-------- frontend/src/core/threads/hooks.ts | 28 ++++++++++ 3 files changed, 71 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index a7a09705..b5fd1806 100644 --- a/Makefile +++ b/Makefile @@ -263,11 +263,11 @@ docker-logs-gateway: # ========================================== # Docker Publish Command # ========================================== -# Usage: make docker-publish VER=v220.20251202 SVC=frontend -# Example: make docker-publish VER=v220.20251202 SVC=frontend +# Usage: make docker-publish VER=[version] SVC=[service name] [PUSH=1] +# Example: make docker-publish VER=v2.0.20251202 SVC=frontend PUSH=0 docker-publish: @if [ -z "$(VER)" ]; then \ - echo "✗ VER is required (e.g. v220.20251202)"; \ + echo "✗ VER is required (e.g. v2.0.20251202)"; \ exit 1; \ fi @if [ -z "$(SVC)" ]; then \ @@ -293,9 +293,13 @@ docker-publish: echo "✗ Docker build failed"; \ exit 1; \ fi; \ - docker push $$IMAGE; \ - if [ $$? -ne 0 ]; then \ - echo "✗ Docker push failed"; \ - exit 1; \ - fi; \ - echo "✓ Docker image $$IMAGE built and pushed successfully" \ No newline at end of file + if [ "$(PUSH)" = "0" ]; then \ + echo "✓ Docker image $$IMAGE built successfully (not pushed)"; \ + else \ + docker push $$IMAGE; \ + if [ $$? -ne 0 ]; then \ + echo "✗ Docker push failed"; \ + exit 1; \ + fi; \ + echo "✓ Docker image $$IMAGE built and pushed successfully"; \ + fi \ No newline at end of file diff --git a/frontend/src/app/workspace/chats/[thread_id]/page.tsx b/frontend/src/app/workspace/chats/[thread_id]/page.tsx index 7b9f9c4b..354aa80b 100644 --- a/frontend/src/app/workspace/chats/[thread_id]/page.tsx +++ b/frontend/src/app/workspace/chats/[thread_id]/page.tsx @@ -32,6 +32,7 @@ import { DevTodoList } from "@/components/workspace/dev-todo-list"; import { IframeTestPanel } from "@/components/workspace/iframe-test-panel"; import { InputBox } from "@/components/workspace/input-box"; import { MessageList } from "@/components/workspace/messages"; +import { MessageListSkeleton } from "@/components/workspace/messages/skeleton"; import { ThreadContext } from "@/components/workspace/messages/context"; import { ThreadTitle } from "@/components/workspace/thread-title"; import { TodoList } from "@/components/workspace/todo-list"; @@ -165,6 +166,10 @@ export default function ChatPage() { const [hasSubmitted, setHasSubmitted] = useState(false); const suppressExistingThreadPrefetchUi = reuseExistingThread && !hasSubmitted; + const suppressNewThreadSubmitUi = + isNewThread && createNewSession && hasSubmitted; + const suppressConversationUi = + suppressExistingThreadPrefetchUi || suppressNewThreadSubmitUi; useEffect(() => { const pageTitle = isNewThread @@ -172,7 +177,7 @@ export default function ChatPage() { : thread.values?.title && thread.values.title !== "Untitled" ? thread.values.title : t.pages.untitled; - if (thread.isThreadLoading && !suppressExistingThreadPrefetchUi) { + if (thread.isThreadLoading && !suppressConversationUi) { document.title = `Loading... - ${t.pages.appName}`; } else { document.title = `${pageTitle} - ${t.pages.appName}`; @@ -184,19 +189,21 @@ export default function ChatPage() { t.pages.appName, thread.values.title, thread.isThreadLoading, - suppressExistingThreadPrefetchUi, + suppressConversationUi, ]); const [autoSelectFirstArtifact, setAutoSelectFirstArtifact] = useState(true); useEffect(() => { - setArtifacts(thread.values.artifacts); - if ( - env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" && - autoSelectFirstArtifact - ) { - if (thread?.values?.artifacts?.length > 0) { - setAutoSelectFirstArtifact(false); - selectArtifact(thread.values.artifacts[0]!); + if (!suppressConversationUi) { + setArtifacts(thread.values.artifacts); + if ( + env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" && + autoSelectFirstArtifact + ) { + if (thread?.values?.artifacts?.length > 0) { + setAutoSelectFirstArtifact(false); + selectArtifact(thread.values.artifacts[0]!); + } } } }, [ @@ -337,20 +344,21 @@ export default function ChatPage() { )} >
- + ) : ( + + } + paddingBottom={todoListCollapsed ? 160 : 280} + /> + )}
diff --git a/frontend/src/core/threads/hooks.ts b/frontend/src/core/threads/hooks.ts index d2542104..1df09deb 100644 --- a/frontend/src/core/threads/hooks.ts +++ b/frontend/src/core/threads/hooks.ts @@ -18,6 +18,29 @@ import type { AgentThreadState, } from "./types"; +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +async function waitForThreadStateToBeReadable( + apiClient: ReturnType, + threadId: string, + timeoutMs = 3000, +) { + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + try { + const state = await apiClient.threads.getState(threadId); + if ((state.values.messages?.length ?? 0) > 0) { + return; + } + } catch { + // Ignore transient 404 / not-ready errors while the new thread is being persisted. + } + + await sleep(100); + } +} + export function useThreadStream({ threadId, isNewThread, @@ -188,6 +211,11 @@ export function useSubmitThread({ }, }, ); + + if (createNewSession && isNewThread && threadId) { + await waitForThreadStateToBeReadable(apiClient, threadId); + } + void queryClient.invalidateQueries({ queryKey: ["threads", "search"] }); afterSubmit?.(); },