fix: 复原isnew逻辑
This commit is contained in:
parent
948c5c7f58
commit
8065dcdd91
|
|
@ -66,9 +66,6 @@ export default function ChatPage() {
|
||||||
!isNewThread ||
|
!isNewThread ||
|
||||||
searchParams.get("xclaw_used")?.trim().toLowerCase() === "true";
|
searchParams.get("xclaw_used")?.trim().toLowerCase() === "true";
|
||||||
|
|
||||||
// Submission strategy: always reuse the thread id from query; never create new.
|
|
||||||
const createNewSession = false;
|
|
||||||
/*
|
|
||||||
// Original strategy:
|
// Original strategy:
|
||||||
// - isnew=false + thread_id: reuse existing thread (explicit request from URL)
|
// - isnew=false + thread_id: reuse existing thread (explicit request from URL)
|
||||||
// - xclaw_used=true: follow `isnew` (isnew=false => reuse existing thread)
|
// - 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") {
|
if (searchParams.get("xclaw_used")?.trim().toLowerCase() !== "true") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return searchParams.get("isnew")?.trim().toLowerCase() !== "false";
|
return searchParams.get("isnew")?.trim().toLowerCase() === "true";
|
||||||
}, [isNewThread, searchParams]);
|
}, [isNewThread, searchParams]);
|
||||||
*/
|
console.log(createNewSession, "createNewSession");
|
||||||
|
const shouldStayOnNewRoute = useMemo(
|
||||||
|
() => searchParams.get("isnew")?.trim().toLowerCase() === "true",
|
||||||
|
[searchParams],
|
||||||
|
);
|
||||||
const streamThreadId = useMemo(() => {
|
const streamThreadId = useMemo(() => {
|
||||||
return isNewThread && createNewSession ? undefined : threadId;
|
return isNewThread && createNewSession ? undefined : threadId;
|
||||||
}, [createNewSession, isNewThread, threadId]);
|
}, [createNewSession, isNewThread, threadId]);
|
||||||
|
|
@ -105,11 +106,14 @@ export default function ChatPage() {
|
||||||
const [thread, sendMessage, isUploading] = useThreadStream({
|
const [thread, sendMessage, isUploading] = useThreadStream({
|
||||||
threadId: streamThreadId,
|
threadId: streamThreadId,
|
||||||
context: settings.context,
|
context: settings.context,
|
||||||
|
createNewSession,
|
||||||
isMock,
|
isMock,
|
||||||
onStart: (currentThreadId) => {
|
onStart: (currentThreadId) => {
|
||||||
setIsNewThread(false);
|
setIsNewThread(false);
|
||||||
|
if (!shouldStayOnNewRoute) {
|
||||||
// Keep /new in history so router.back() can return to it.
|
// Keep /new in history so router.back() can return to it.
|
||||||
router.replace(`/workspace/chats/${currentThreadId}`);
|
router.replace(`/workspace/chats/${currentThreadId}`);
|
||||||
|
}
|
||||||
// history.pushState(null, "", pathOfThread(currentThreadId));
|
// history.pushState(null, "", pathOfThread(currentThreadId));
|
||||||
},
|
},
|
||||||
onFinish: (state) => {
|
onFinish: (state) => {
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,8 @@ export function useThreadChat() {
|
||||||
}
|
}
|
||||||
return value === "new" ? queryThreadIdFromParams : value;
|
return value === "new" ? queryThreadIdFromParams : value;
|
||||||
};
|
};
|
||||||
const xClawUsedFromQuery = searchParams.get("xclaw_used");
|
const isNewRequested =
|
||||||
const isNewFromQuery =
|
searchParams.get("isnew")?.trim().toLowerCase() === "true";
|
||||||
searchParams.get("isnew")?.trim().toLowerCase() === "false";
|
|
||||||
const effectiveThreadIdFromPath =
|
const effectiveThreadIdFromPath =
|
||||||
normalizeThreadId(threadIdFromPath) ?? readStoredThreadId();
|
normalizeThreadId(threadIdFromPath) ?? readStoredThreadId();
|
||||||
// console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath);
|
// console.log("[useThreadChat] effectiveThreadIdFromPath", effectiveThreadIdFromPath);
|
||||||
|
|
@ -71,28 +70,18 @@ export function useThreadChat() {
|
||||||
return effectiveThreadIdFromPath ?? undefined;
|
return effectiveThreadIdFromPath ?? undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
// /new 或缺少 query 的 thread_id 时,视为新会话状态。 但是这个并不是新会话的意思,而是说当前处在对话状态。
|
// New session is only controlled by `isnew=true`.
|
||||||
const [isNewThread, setIsNewThread] = useState(
|
const [isNewThread, setIsNewThread] = useState(() => isNewRequested);
|
||||||
() => threadIdFromPath === "new" || !queryThreadIdFromParams,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 记住最近一次有效的 thread_id,供下次加载兜底使用。
|
// 记住最近一次有效的 thread_id,供下次加载兜底使用。
|
||||||
if (threadId && threadId !== "new" && typeof window !== "undefined") {
|
if (threadId && threadId !== "new" && typeof window !== "undefined") {
|
||||||
window.sessionStorage.setItem("workspace.thread_id", threadId);
|
window.sessionStorage.setItem("workspace.thread_id", threadId);
|
||||||
}
|
}
|
||||||
if (pathname.endsWith("/new")) {
|
setIsNewThread(
|
||||||
setIsNewThread(true);
|
searchParams.get("isnew")?.trim().toLowerCase() === "true",
|
||||||
const nextQueryThreadId = readQueryThreadId();
|
);
|
||||||
const nextIsNewFromQuery =
|
// Prefer path thread id, fall back to query thread_id when path is /new.
|
||||||
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));
|
|
||||||
|
|
||||||
setThreadId(normalizeThreadId(threadIdFromPath));
|
setThreadId(normalizeThreadId(threadIdFromPath));
|
||||||
}, [pathname, router, searchParams, threadIdFromPath]);
|
}, [pathname, router, searchParams, threadIdFromPath]);
|
||||||
const isMock = searchParams.get("mock") === "true";
|
const isMock = searchParams.get("mock") === "true";
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ export type ToolEndEvent = {
|
||||||
export type ThreadStreamOptions = {
|
export type ThreadStreamOptions = {
|
||||||
threadId?: string | null | undefined;
|
threadId?: string | null | undefined;
|
||||||
context: LocalSettings["context"];
|
context: LocalSettings["context"];
|
||||||
|
createNewSession?: boolean;
|
||||||
isMock?: boolean;
|
isMock?: boolean;
|
||||||
onStart?: (threadId: string) => void;
|
onStart?: (threadId: string) => void;
|
||||||
onFinish?: (state: AgentThreadState) => void;
|
onFinish?: (state: AgentThreadState) => void;
|
||||||
|
|
@ -128,6 +129,7 @@ export function useThreadStreamLegacy({
|
||||||
export function useThreadStream({
|
export function useThreadStream({
|
||||||
threadId,
|
threadId,
|
||||||
context,
|
context,
|
||||||
|
createNewSession = false,
|
||||||
isMock,
|
isMock,
|
||||||
onStart,
|
onStart,
|
||||||
onFinish,
|
onFinish,
|
||||||
|
|
@ -179,9 +181,10 @@ export function useThreadStream({
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const updateSubtask = useUpdateSubtask();
|
const updateSubtask = useUpdateSubtask();
|
||||||
|
const apiClient = getAPIClient(isMock);
|
||||||
|
|
||||||
const thread = useStream<AgentThreadState>({
|
const thread = useStream<AgentThreadState>({
|
||||||
client: getAPIClient(isMock),
|
client: apiClient,
|
||||||
assistantId: "lead_agent",
|
assistantId: "lead_agent",
|
||||||
threadId: onStreamThreadId,
|
threadId: onStreamThreadId,
|
||||||
reconnectOnMount: true,
|
reconnectOnMount: true,
|
||||||
|
|
@ -329,6 +332,11 @@ export function useThreadStream({
|
||||||
let uploadedFileInfo: UploadedFileInfo[] = [];
|
let uploadedFileInfo: UploadedFileInfo[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// isnew 为 true 时,删除旧线程并创建同名新线程
|
||||||
|
if (createNewSession && resolvedThreadId) {
|
||||||
|
await apiClient.threads.delete(resolvedThreadId).catch(() => undefined);
|
||||||
|
}
|
||||||
|
|
||||||
// Upload files first if any
|
// Upload files first if any
|
||||||
if (message.files && message.files.length > 0) {
|
if (message.files && message.files.length > 0) {
|
||||||
setIsUploading(true);
|
setIsUploading(true);
|
||||||
|
|
@ -474,7 +482,15 @@ export function useThreadStream({
|
||||||
sendInFlightRef.current = false;
|
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
|
// Merge thread with optimistic messages for display
|
||||||
|
|
@ -524,11 +540,11 @@ export function useSubmitThread({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (createNewSession && threadId) {
|
if (createNewSession && threadId) {
|
||||||
try {
|
await apiClient.threads.delete(threadId).catch(() => undefined);
|
||||||
await apiClient.threads.delete(threadId);
|
await apiClient.threads.create({
|
||||||
} catch {
|
threadId,
|
||||||
// Ignore delete errors
|
ifExists: "do_nothing",
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.files && message.files.length > 0) {
|
if (message.files && message.files.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export function useIframeSkill(): UseIframeSkillReturn {
|
||||||
const titleFromQuery = searchParams.get("title");
|
const titleFromQuery = searchParams.get("title");
|
||||||
const threadIdFromQuery = searchParams.get("thread_id");
|
const threadIdFromQuery = searchParams.get("thread_id");
|
||||||
const xClawUsedFromQuery = searchParams.get("xclaw_used");
|
const xClawUsedFromQuery = searchParams.get("xclaw_used");
|
||||||
|
const isNewFromQuery = searchParams.get("isnew")?.trim().toLowerCase() === "true";
|
||||||
const lastThreadIdRef = useRef<string | null>(null);
|
const lastThreadIdRef = useRef<string | null>(null);
|
||||||
|
|
||||||
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
|
const [selectedSkill, setSelectedSkill] = useState<SkillData | null>(null);
|
||||||
|
|
@ -45,10 +46,11 @@ export function useIframeSkill(): UseIframeSkillReturn {
|
||||||
|
|
||||||
if (!threadIdFromQuery) return;
|
if (!threadIdFromQuery) return;
|
||||||
if (xClawUsedFromQuery !== "true") return;
|
if (xClawUsedFromQuery !== "true") return;
|
||||||
|
if (isNewFromQuery) return;
|
||||||
if (lastThreadIdRef.current === threadIdFromQuery) return;
|
if (lastThreadIdRef.current === threadIdFromQuery) return;
|
||||||
lastThreadIdRef.current = threadIdFromQuery;
|
lastThreadIdRef.current = threadIdFromQuery;
|
||||||
router.replace(`/workspace/chats/${threadIdFromQuery}`);
|
router.replace(`/workspace/chats/${threadIdFromQuery}`);
|
||||||
}, [router, threadIdFromQuery, xClawUsedFromQuery]);
|
}, [isNewFromQuery, router, threadIdFromQuery, xClawUsedFromQuery]);
|
||||||
|
|
||||||
// 2. 监听宿主页 postMessage
|
// 2. 监听宿主页 postMessage
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue