fix(web): restore last active chat session

This commit is contained in:
XYSK-lilong007 2026-03-12 02:33:13 +08:00
parent 4a8a2e9c23
commit 2b25f7fb48

View file

@ -26,6 +26,22 @@ export interface ChatMessage {
type ConnectionState = "disconnected" | "connecting" | "connected" | "error" type ConnectionState = "disconnected" | "connecting" | "connected" | "error"
const LAST_SESSION_STORAGE_KEY = "picoclaw:last-session-id"
function readStoredSessionId(): string {
const value = localStorage.getItem(LAST_SESSION_STORAGE_KEY)?.trim()
return value || ""
}
function writeStoredSessionId(sessionId: string) {
if (sessionId) {
localStorage.setItem(LAST_SESSION_STORAGE_KEY, sessionId)
return
}
localStorage.removeItem(LAST_SESSION_STORAGE_KEY)
}
function generateSessionId(): string { function generateSessionId(): string {
const webCrypto = globalThis.crypto const webCrypto = globalThis.crypto
if (webCrypto && typeof webCrypto.randomUUID === "function") { if (webCrypto && typeof webCrypto.randomUUID === "function") {
@ -109,18 +125,67 @@ export function usePicoChat() {
useState<ConnectionState>("disconnected") useState<ConnectionState>("disconnected")
const [isTyping, setIsTyping] = useState(false) const [isTyping, setIsTyping] = useState(false)
const [activeSessionId, setActiveSessionId] = const [activeSessionId, setActiveSessionId] =
useState<string>(generateSessionId) useState<string>(() => readStoredSessionId() || generateSessionId())
const wsRef = useRef<WebSocket | null>(null) const wsRef = useRef<WebSocket | null>(null)
const isConnectingRef = useRef(false) const isConnectingRef = useRef(false)
const msgIdCounter = useRef(0) const msgIdCounter = useRef(0)
const activeSessionIdRef = useRef(activeSessionId) const activeSessionIdRef = useRef(activeSessionId)
const hydratedInitialSessionRef = useRef(false)
// Keep ref in sync // Keep ref in sync
useEffect(() => { useEffect(() => {
activeSessionIdRef.current = activeSessionId activeSessionIdRef.current = activeSessionId
writeStoredSessionId(activeSessionId)
}, [activeSessionId]) }, [activeSessionId])
const loadSessionMessages = useCallback(async (sessionId: string) => {
const detail = await getSessionHistory(sessionId)
const fallbackTime = detail.updated
return detail.messages.map((m, i) => ({
id: `hist-${i}-${Date.now()}`,
role: m.role as "user" | "assistant",
content: m.content,
timestamp: fallbackTime,
}))
}, [])
useEffect(() => {
if (hydratedInitialSessionRef.current) {
return
}
hydratedInitialSessionRef.current = true
const storedSessionId = readStoredSessionId()
if (!storedSessionId) {
return
}
let cancelled = false
void loadSessionMessages(storedSessionId)
.then((historyMessages) => {
if (cancelled) {
return
}
setMessages(historyMessages)
setIsTyping(false)
})
.catch((err) => {
console.error("Failed to restore last session history:", err)
if (cancelled) {
return
}
localStorage.removeItem(LAST_SESSION_STORAGE_KEY)
setMessages([])
setIsTyping(false)
})
return () => {
cancelled = true
}
}, [loadSessionMessages])
const handlePicoMessage = useCallback((msg: PicoMessage) => { const handlePicoMessage = useCallback((msg: PicoMessage) => {
const payload = msg.payload || {} const payload = msg.payload || {}
@ -325,14 +390,7 @@ export function usePicoChat() {
} }
try { try {
const detail = await getSessionHistory(sessionId) const historyMessages = await loadSessionMessages(sessionId)
const fallbackTime = detail.updated
const historyMessages = detail.messages.map((m, i) => ({
id: `hist-${i}-${Date.now()}`,
role: m.role as "user" | "assistant",
content: m.content,
timestamp: fallbackTime,
}))
// Only switch the active websocket session after history has loaded successfully. // Only switch the active websocket session after history has loaded successfully.
disconnect() disconnect()
@ -351,7 +409,7 @@ export function usePicoChat() {
} }
}, 100) }, 100)
}, },
[connect, disconnect, gatewayState, t], [connect, disconnect, gatewayState, loadSessionMessages, t],
) )
// Start a new empty chat // Start a new empty chat