chat: persist last session and require sessionId
parent
3110c0275f
commit
3d60016d87
|
|
@ -14,6 +14,8 @@ import { useChatData } from './hooks/useChatData';
|
||||||
import { useChatSender } from './hooks/useChatSender';
|
import { useChatSender } from './hooks/useChatSender';
|
||||||
import { markdownToPlainText } from './utils/copy';
|
import { markdownToPlainText } from './utils/copy';
|
||||||
|
|
||||||
|
const lastSessionKey = (agentId: string) => `chat:lastSession:${agentId}`;
|
||||||
|
|
||||||
export default function ChatPage() {
|
export default function ChatPage() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -33,18 +35,70 @@ export default function ChatPage() {
|
||||||
const { bodyRef, scrollBottom, initialScrollDoneRef } = useChatScroll();
|
const { bodyRef, scrollBottom, initialScrollDoneRef } = useChatScroll();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
const s = searchParams.get('session');
|
const s = searchParams.get('session');
|
||||||
const m = searchParams.get('msg');
|
const m = searchParams.get('msg');
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
setSessionId(s);
|
setSessionId(s);
|
||||||
if (m) setHighlightId(m);
|
try {
|
||||||
const next = new URLSearchParams(searchParams);
|
localStorage.setItem(lastSessionKey(id), s);
|
||||||
next.delete('session');
|
} catch {
|
||||||
next.delete('msg');
|
// ignore
|
||||||
setSearchParams(next, { replace: true });
|
}
|
||||||
|
if (m) {
|
||||||
|
setHighlightId(m);
|
||||||
|
const next = new URLSearchParams(searchParams);
|
||||||
|
next.delete('msg');
|
||||||
|
setSearchParams(next, { replace: true });
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saved = (() => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(lastSessionKey(id));
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
if (saved) {
|
||||||
|
setSessionId(saved);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const list = await SessionAPI.list(id, '0');
|
||||||
|
if (list.length > 0) {
|
||||||
|
setSessionId(list[0].id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const created = await SessionAPI.create(id);
|
||||||
|
setSessionId(created.id);
|
||||||
|
} catch (e: any) {
|
||||||
|
message.error('加载会话失败:' + (e?.message ?? e));
|
||||||
|
}
|
||||||
|
})();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [searchParams]);
|
}, [id]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!id || !sessionId) return;
|
||||||
|
try {
|
||||||
|
localStorage.setItem(lastSessionKey(id), sessionId);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
const cur = searchParams.get('session');
|
||||||
|
if (cur === sessionId) return;
|
||||||
|
const next = new URLSearchParams(searchParams);
|
||||||
|
next.set('session', sessionId);
|
||||||
|
next.delete('msg');
|
||||||
|
setSearchParams(next, { replace: true });
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [id, sessionId]);
|
||||||
|
|
||||||
const { agent, agentList, messages, setMessages, branches, setBranches, loadMessages } = useChatData({
|
const { agent, agentList, messages, setMessages, branches, setBranches, loadMessages } = useChatData({
|
||||||
agentId: id,
|
agentId: id,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function useChatData(args: {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadMessages = async () => {
|
const loadMessages = async () => {
|
||||||
if (!agentId) return;
|
if (!agentId || !sessionId) return;
|
||||||
const his = await ChatAPI.history(agentId, sessionId || undefined);
|
const his = await ChatAPI.history(agentId, sessionId || undefined);
|
||||||
setMessages(Array.isArray(his.messages) ? his.messages : []);
|
setMessages(Array.isArray(his.messages) ? his.messages : []);
|
||||||
setBranches(his.branches || {});
|
setBranches(his.branches || {});
|
||||||
|
|
@ -92,7 +92,7 @@ export function useChatData(args: {
|
||||||
}, [agentId]);
|
}, [agentId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!agentId) return;
|
if (!agentId || !sessionId) return;
|
||||||
loadMessages();
|
loadMessages();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [sessionId, highlightId, agentId]);
|
}, [sessionId, highlightId, agentId]);
|
||||||
|
|
@ -107,4 +107,3 @@ export function useChatData(args: {
|
||||||
loadMessages
|
loadMessages
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ export function useChatSender(args: {
|
||||||
|
|
||||||
const handleSendStream = async (text: string) => {
|
const handleSendStream = async (text: string) => {
|
||||||
if (!agentId) return;
|
if (!agentId) return;
|
||||||
|
if (!sessionId) {
|
||||||
|
notify.error('会话未初始化,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const tempUser: ChatMessage = { id: 'tmp-' + Date.now(), role: 'user', content: text, createdAt: Date.now() };
|
const tempUser: ChatMessage = { id: 'tmp-' + Date.now(), role: 'user', content: text, createdAt: Date.now() };
|
||||||
args.setMessages((m) => [...(m || []), tempUser]);
|
args.setMessages((m) => [...(m || []), tempUser]);
|
||||||
setStreaming({ active: true, reasoningText: '', answerText: '', errorMessage: null, retryInfo: null, retrieved: [], toolCalls: [] });
|
setStreaming({ active: true, reasoningText: '', answerText: '', errorMessage: null, retryInfo: null, retrieved: [], toolCalls: [] });
|
||||||
|
|
@ -144,7 +148,7 @@ export function useChatSender(args: {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ctrl.signal,
|
ctrl.signal,
|
||||||
sessionId || undefined,
|
sessionId,
|
||||||
model,
|
model,
|
||||||
modelId,
|
modelId,
|
||||||
imageUrls
|
imageUrls
|
||||||
|
|
@ -167,6 +171,10 @@ export function useChatSender(args: {
|
||||||
|
|
||||||
const handleSendNonStream = async (text: string) => {
|
const handleSendNonStream = async (text: string) => {
|
||||||
if (!agentId) return;
|
if (!agentId) return;
|
||||||
|
if (!sessionId) {
|
||||||
|
notify.error('会话未初始化,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const tempUser: ChatMessage = { id: 'tmp-' + Date.now(), role: 'user', content: text, createdAt: Date.now() };
|
const tempUser: ChatMessage = { id: 'tmp-' + Date.now(), role: 'user', content: text, createdAt: Date.now() };
|
||||||
args.setMessages((m) => [...(m || []), tempUser]);
|
args.setMessages((m) => [...(m || []), tempUser]);
|
||||||
scrollBottom(true);
|
scrollBottom(true);
|
||||||
|
|
@ -174,7 +182,7 @@ export function useChatSender(args: {
|
||||||
const content = attText ? `${text}\n\n${attText}` : text;
|
const content = attText ? `${text}\n\n${attText}` : text;
|
||||||
const model = overrides.model || agentModels[0]?.name || '';
|
const model = overrides.model || agentModels[0]?.name || '';
|
||||||
try {
|
try {
|
||||||
const res = await ChatAPI.send(agentId, content, sessionId || undefined, model, imageUrls);
|
const res = await ChatAPI.send(agentId, content, sessionId, model, imageUrls);
|
||||||
args.setMessages((m) => [...(m || []).filter((x) => x.id !== tempUser.id), res.user, res.assistant]);
|
args.setMessages((m) => [...(m || []).filter((x) => x.id !== tempUser.id), res.user, res.assistant]);
|
||||||
setSessionRefresh((t) => t + 1);
|
setSessionRefresh((t) => t + 1);
|
||||||
setAttachments([]);
|
setAttachments([]);
|
||||||
|
|
@ -206,7 +214,11 @@ export function useChatSender(args: {
|
||||||
|
|
||||||
const handleClear = async () => {
|
const handleClear = async () => {
|
||||||
if (!agentId) return;
|
if (!agentId) return;
|
||||||
await ChatAPI.clear(agentId, sessionId || undefined);
|
if (!sessionId) {
|
||||||
|
notify.error('会话未初始化,请稍后重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await ChatAPI.clear(agentId, sessionId);
|
||||||
args.setMessages(() => []);
|
args.setMessages(() => []);
|
||||||
setBranches({});
|
setBranches({});
|
||||||
notify.success('对话已清空');
|
notify.success('对话已清空');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue