fix(frontend): 进入/new预创建会话并强制跳转聊天态
This commit is contained in:
parent
751cb50a46
commit
87b73e2b08
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
import { FilesIcon, ListTodoIcon, XIcon } from "lucide-react";
|
import { FilesIcon, ListTodoIcon, XIcon } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
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 { ConversationEmptyState } from "@/components/ai-elements/conversation";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
@ -28,6 +29,7 @@ import { ThreadTitle } from "@/components/workspace/thread-title";
|
||||||
import { Tooltip } from "@/components/workspace/tooltip";
|
import { Tooltip } from "@/components/workspace/tooltip";
|
||||||
import { useSpecificChatMode } from "@/components/workspace/use-chat-mode";
|
import { useSpecificChatMode } from "@/components/workspace/use-chat-mode";
|
||||||
import { Welcome } from "@/components/workspace/welcome";
|
import { Welcome } from "@/components/workspace/welcome";
|
||||||
|
import { getAPIClient } from "@/core/api";
|
||||||
import { useI18n } from "@/core/i18n/hooks";
|
import { useI18n } from "@/core/i18n/hooks";
|
||||||
import { POST_MESSAGE_TYPES, sendToParent } from "@/core/iframe-messages";
|
import { POST_MESSAGE_TYPES, sendToParent } from "@/core/iframe-messages";
|
||||||
import { useNotification } from "@/core/notification/hooks";
|
import { useNotification } from "@/core/notification/hooks";
|
||||||
|
|
@ -66,13 +68,18 @@ export default function ChatPage() {
|
||||||
|
|
||||||
// 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/is_chatting 参数。
|
// 新逻辑:历史渲染和新会话仅由路由 /chats/new 控制,不再读取 isnew/is_chatting 参数。
|
||||||
const shouldRenderHistory = !showWelcomeStyle;
|
const shouldRenderHistory = !showWelcomeStyle;
|
||||||
const createNewSession = useMemo(() => isNewThread, [isNewThread]);
|
|
||||||
const safeThreadId = useMemo(() => {
|
const safeThreadId = useMemo(() => {
|
||||||
if (!threadId || threadId === "new") {
|
if (!threadId || threadId === "new") {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return threadId;
|
return threadId;
|
||||||
}, [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(() => {
|
const streamThreadId = useMemo(() => {
|
||||||
if (isNewThread && createNewSession) {
|
if (isNewThread && createNewSession) {
|
||||||
|
|
@ -80,9 +87,38 @@ export default function ChatPage() {
|
||||||
}
|
}
|
||||||
return safeThreadId;
|
return safeThreadId;
|
||||||
}, [createNewSession, isNewThread, safeThreadId]);
|
}, [createNewSession, isNewThread, safeThreadId]);
|
||||||
|
const apiClient = useMemo(() => getAPIClient(isMock), [isMock]);
|
||||||
|
const warnedMissingThreadIdRef = useRef(false);
|
||||||
|
const initializedThreadRef = useRef<string | null>(null);
|
||||||
|
|
||||||
const { showNotification } = useNotification();
|
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 消息
|
// 监听宿主页 selectedSkill 消息
|
||||||
const {
|
const {
|
||||||
skillError: selectedSkillError,
|
skillError: selectedSkillError,
|
||||||
|
|
@ -205,10 +241,24 @@ export default function ChatPage() {
|
||||||
if (isSelectedSkillBootstrapping) {
|
if (isSelectedSkillBootstrapping) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (isNewThread && !safeThreadId) {
|
||||||
|
toast.error("缺少 thread_id,无法发送消息");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setHasSubmitted(true);
|
setHasSubmitted(true);
|
||||||
|
if (safeThreadId && (isNewThread || showWelcomeStyle)) {
|
||||||
|
router.replace(`/workspace/chats/${safeThreadId}?is_chatting=true`);
|
||||||
|
}
|
||||||
void sendMessage(safeThreadId, message);
|
void sendMessage(safeThreadId, message);
|
||||||
},
|
},
|
||||||
[isSelectedSkillBootstrapping, safeThreadId, sendMessage],
|
[
|
||||||
|
isNewThread,
|
||||||
|
isSelectedSkillBootstrapping,
|
||||||
|
router,
|
||||||
|
safeThreadId,
|
||||||
|
sendMessage,
|
||||||
|
showWelcomeStyle,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
const handleStop = useCallback(async () => {
|
const handleStop = useCallback(async () => {
|
||||||
await thread.stop();
|
await thread.stop();
|
||||||
|
|
@ -456,7 +506,8 @@ export default function ChatPage() {
|
||||||
disabled={
|
disabled={
|
||||||
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ||
|
env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ||
|
||||||
isSelectedSkillBootstrapping ||
|
isSelectedSkillBootstrapping ||
|
||||||
isUploading
|
isUploading ||
|
||||||
|
(isNewThread && !safeThreadId)
|
||||||
}
|
}
|
||||||
onContextChange={(context) => setSettings("context", context)}
|
onContextChange={(context) => setSettings("context", context)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export function WorkspaceHeader({ className }: { className?: string }) {
|
||||||
) : (
|
) : (
|
||||||
<div className="text-primary ml-2 cursor-default font-serif">
|
<div className="text-primary ml-2 cursor-default font-serif">
|
||||||
{/* TODO: 测试标识 */}
|
{/* 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>
|
</div>
|
||||||
)}
|
)}
|
||||||
<SidebarTrigger />
|
<SidebarTrigger />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue