fix(frontend): 进入/new预创建会话并强制跳转聊天态

This commit is contained in:
肖应宇 2026-04-09 13:29:46 +08:00 committed by Titan
parent 751cb50a46
commit 87b73e2b08
2 changed files with 56 additions and 5 deletions

View File

@ -2,7 +2,8 @@
import { FilesIcon, ListTodoIcon, XIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { ConversationEmptyState } from "@/components/ai-elements/conversation";
import { Button } from "@/components/ui/button";
@ -28,6 +29,7 @@ import { ThreadTitle } from "@/components/workspace/thread-title";
import { Tooltip } from "@/components/workspace/tooltip";
import { useSpecificChatMode } from "@/components/workspace/use-chat-mode";
import { Welcome } from "@/components/workspace/welcome";
import { getAPIClient } from "@/core/api";
import { useI18n } from "@/core/i18n/hooks";
import { POST_MESSAGE_TYPES, sendToParent } from "@/core/iframe-messages";
import { useNotification } from "@/core/notification/hooks";
@ -66,13 +68,18 @@ export default function ChatPage() {
// 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/is_chatting 参数。
const shouldRenderHistory = !showWelcomeStyle;
const createNewSession = useMemo(() => isNewThread, [isNewThread]);
const safeThreadId = useMemo(() => {
if (!threadId || threadId === "new") {
return undefined;
}
return threadId;
}, [threadId]);
// `/new` + `thread_id` now reuses the pre-created thread, instead of creating
// a new session on first submit.
const createNewSession = useMemo(
() => isNewThread && !safeThreadId,
[isNewThread, safeThreadId],
);
const streamThreadId = useMemo(() => {
if (isNewThread && createNewSession) {
@ -80,9 +87,38 @@ export default function ChatPage() {
}
return safeThreadId;
}, [createNewSession, isNewThread, safeThreadId]);
const apiClient = useMemo(() => getAPIClient(isMock), [isMock]);
const warnedMissingThreadIdRef = useRef(false);
const initializedThreadRef = useRef<string | null>(null);
const { showNotification } = useNotification();
useEffect(() => {
if (!isNewThread) {
warnedMissingThreadIdRef.current = false;
return;
}
if (!safeThreadId) {
if (!warnedMissingThreadIdRef.current) {
warnedMissingThreadIdRef.current = true;
toast.error("缺少 thread_id无法创建会话");
}
return;
}
warnedMissingThreadIdRef.current = false;
if (initializedThreadRef.current === safeThreadId) return;
initializedThreadRef.current = safeThreadId;
void apiClient.threads
.create({
threadId: safeThreadId,
ifExists: "do_nothing",
})
.catch(() => {
initializedThreadRef.current = null;
toast.error("会话创建失败,请稍后重试");
});
}, [apiClient, isNewThread, safeThreadId]);
// 监听宿主页 selectedSkill 消息
const {
skillError: selectedSkillError,
@ -205,10 +241,24 @@ export default function ChatPage() {
if (isSelectedSkillBootstrapping) {
return;
}
if (isNewThread && !safeThreadId) {
toast.error("缺少 thread_id无法发送消息");
return;
}
setHasSubmitted(true);
if (safeThreadId && (isNewThread || showWelcomeStyle)) {
router.replace(`/workspace/chats/${safeThreadId}?is_chatting=true`);
}
void sendMessage(safeThreadId, message);
},
[isSelectedSkillBootstrapping, safeThreadId, sendMessage],
[
isNewThread,
isSelectedSkillBootstrapping,
router,
safeThreadId,
sendMessage,
showWelcomeStyle,
],
);
const handleStop = useCallback(async () => {
await thread.stop();
@ -456,7 +506,8 @@ export default function ChatPage() {
disabled={
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ||
isSelectedSkillBootstrapping ||
isUploading
isUploading ||
(isNewThread && !safeThreadId)
}
onContextChange={(context) => setSettings("context", context)}
onSubmit={handleSubmit}

View File

@ -43,7 +43,7 @@ export function WorkspaceHeader({ className }: { className?: string }) {
) : (
<div className="text-primary ml-2 cursor-default font-serif">
{/* TODO: 测试标识 */}
XClaw <span className="text-sm text-[#000000c5]">v3.2.1 dev: 给通信面板加收起按钮</span>
XClaw <span className="text-sm text-[#000000c5]">v3.2.1 fix(frontend): /new预创建会话并强制跳转聊天态</span>
</div>
)}
<SidebarTrigger />