fix: 复原isnew逻辑

This commit is contained in:
肖应宇 2026-04-01 20:24:56 +08:00
parent 948c5c7f58
commit 8065dcdd91
4 changed files with 45 additions and 34 deletions

View File

@ -66,9 +66,6 @@ export default function ChatPage() {
!isNewThread ||
searchParams.get("xclaw_used")?.trim().toLowerCase() === "true";
// Submission strategy: always reuse the thread id from query; never create new.
const createNewSession = false;
/*
// Original strategy:
// - isnew=false + thread_id: reuse existing thread (explicit request from URL)
// - xclaw_used=true: follow `isnew` (isnew=false => reuse existing thread)
@ -87,9 +84,13 @@ export default function ChatPage() {
if (searchParams.get("xclaw_used")?.trim().toLowerCase() !== "true") {
return true;
}
return searchParams.get("isnew")?.trim().toLowerCase() !== "false";
return searchParams.get("isnew")?.trim().toLowerCase() === "true";
}, [isNewThread, searchParams]);
*/
console.log(createNewSession, "createNewSession");
const shouldStayOnNewRoute = useMemo(
() => searchParams.get("isnew")?.trim().toLowerCase() === "true",
[searchParams],
);
const streamThreadId = useMemo(() => {
return isNewThread && createNewSession ? undefined : threadId;
}, [createNewSession, isNewThread, threadId]);
@ -105,11 +106,14 @@ export default function ChatPage() {
const [thread, sendMessage, isUploading] = useThreadStream({
threadId: streamThreadId,
context: settings.context,
createNewSession,
isMock,
onStart: (currentThreadId) => {
setIsNewThread(false);
// Keep /new in history so router.back() can return to it.
router.replace(`/workspace/chats/${currentThreadId}`);
if (!shouldStayOnNewRoute) {
// Keep /new in history so router.back() can return to it.
router.replace(`/workspace/chats/${currentThreadId}`);
}
// history.pushState(null, "", pathOfThread(currentThreadId));
},
onFinish: (state) => {

View File

@ -60,9 +60,8 @@ export function useThreadChat() {
}
return value === "new" ? queryThreadIdFromParams : value;
};
const xClawUsedFromQuery = searchParams.get("xclaw_used");
const isNewFromQuery =
searchParams.get("isnew")?.trim().toLowerCase() === "false";
const isNewRequested =
searchParams.get("isnew")?.trim().toLowerCase() === "true";
const effectiveThreadIdFromPath =
normalizeThreadId(threadIdFromPath) ?? readStoredThreadId();
// console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath);
@ -71,28 +70,18 @@ export function useThreadChat() {
return effectiveThreadIdFromPath ?? undefined;
});
// /new 或缺少 query 的 thread_id 时,视为新会话状态。 但是这个并不是新会话的意思,而是说当前处在对话状态。
const [isNewThread, setIsNewThread] = useState(
() => threadIdFromPath === "new" || !queryThreadIdFromParams,
);
// New session is only controlled by `isnew=true`.
const [isNewThread, setIsNewThread] = useState(() => isNewRequested);
useEffect(() => {
// 记住最近一次有效的 thread_id供下次加载兜底使用。
if (threadId && threadId !== "new" && typeof window !== "undefined") {
window.sessionStorage.setItem("workspace.thread_id", threadId);
}
if (pathname.endsWith("/new")) {
setIsNewThread(true);
const nextQueryThreadId = readQueryThreadId();
const nextIsNewFromQuery =
searchParams.get("isnew")?.trim().toLowerCase() === "false";
const nextXClawUsed = searchParams.get("xclaw_used");
setThreadId(nextQueryThreadId ?? undefined);
return;
}
setIsNewThread(false);
// console.log("threadIdFromPath", threadIdFromPath, "normalized", normalizeThreadId(threadIdFromPath));
setIsNewThread(
searchParams.get("isnew")?.trim().toLowerCase() === "true",
);
// Prefer path thread id, fall back to query thread_id when path is /new.
setThreadId(normalizeThreadId(threadIdFromPath));
}, [pathname, router, searchParams, threadIdFromPath]);
const isMock = searchParams.get("mock") === "true";

View File

@ -31,6 +31,7 @@ export type ToolEndEvent = {
export type ThreadStreamOptions = {
threadId?: string | null | undefined;
context: LocalSettings["context"];
createNewSession?: boolean;
isMock?: boolean;
onStart?: (threadId: string) => void;
onFinish?: (state: AgentThreadState) => void;
@ -128,6 +129,7 @@ export function useThreadStreamLegacy({
export function useThreadStream({
threadId,
context,
createNewSession = false,
isMock,
onStart,
onFinish,
@ -179,9 +181,10 @@ export function useThreadStream({
const queryClient = useQueryClient();
const updateSubtask = useUpdateSubtask();
const apiClient = getAPIClient(isMock);
const thread = useStream<AgentThreadState>({
client: getAPIClient(isMock),
client: apiClient,
assistantId: "lead_agent",
threadId: onStreamThreadId,
reconnectOnMount: true,
@ -329,6 +332,11 @@ export function useThreadStream({
let uploadedFileInfo: UploadedFileInfo[] = [];
try {
// isnew 为 true 时,删除旧线程并创建同名新线程
if (createNewSession && resolvedThreadId) {
await apiClient.threads.delete(resolvedThreadId).catch(() => undefined);
}
// Upload files first if any
if (message.files && message.files.length > 0) {
setIsUploading(true);
@ -474,7 +482,15 @@ export function useThreadStream({
sendInFlightRef.current = false;
}
},
[thread, _handleOnStart, t.uploads.uploadingFiles, context, queryClient],
[
thread,
_handleOnStart,
t.uploads.uploadingFiles,
context,
queryClient,
apiClient,
createNewSession,
],
);
// Merge thread with optimistic messages for display
@ -524,11 +540,11 @@ export function useSubmitThread({
}
if (createNewSession && threadId) {
try {
await apiClient.threads.delete(threadId);
} catch {
// Ignore delete errors
}
await apiClient.threads.delete(threadId).catch(() => undefined);
await apiClient.threads.create({
threadId,
ifExists: "do_nothing",
});
}
if (message.files && message.files.length > 0) {

View File

@ -29,6 +29,7 @@ export function useIframeSkill(): UseIframeSkillReturn {
const titleFromQuery = searchParams.get("title");
const threadIdFromQuery = searchParams.get("thread_id");
const xClawUsedFromQuery = searchParams.get("xclaw_used");
const isNewFromQuery = searchParams.get("isnew")?.trim().toLowerCase() === "true";
const lastThreadIdRef = useRef<string | null>(null);
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
@ -45,10 +46,11 @@ export function useIframeSkill(): UseIframeSkillReturn {
if (!threadIdFromQuery) return;
if (xClawUsedFromQuery !== "true") return;
if (isNewFromQuery) return;
if (lastThreadIdRef.current === threadIdFromQuery) return;
lastThreadIdRef.current = threadIdFromQuery;
router.replace(`/workspace/chats/${threadIdFromQuery}`);
}, [router, threadIdFromQuery, xClawUsedFromQuery]);
}, [isNewFromQuery, router, threadIdFromQuery, xClawUsedFromQuery]);
// 2. 监听宿主页 postMessage
useEffect(() => {