Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 4,188 Bytes
67b16c6 962191f 67b16c6 79b2fcc 27da720 962191f 67b16c6 27da720 67b16c6 79b2fcc 962191f 67b16c6 962191f 67b16c6 27da720 67b16c6 79b2fcc 67b16c6 79b2fcc 67b16c6 79b2fcc 67b16c6 79b2fcc 67b16c6 27da720 67b16c6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { SessionMeta } from '@/types/agent';
import { deleteMessages, moveMessages } from '@/lib/chat-message-store';
import { moveBackendMessages, deleteBackendMessages } from '@/lib/backend-message-store';
interface SessionStore {
sessions: SessionMeta[];
activeSessionId: string | null;
// Actions
createSession: (id: string) => void;
deleteSession: (id: string) => void;
switchSession: (id: string) => void;
setSessionActive: (id: string, isActive: boolean) => void;
updateSessionTitle: (id: string, title: string) => void;
setNeedsAttention: (id: string, needs: boolean) => void;
/** Mark a session as expired (backend no longer has it). The UI shows a
* recovery banner and disables input. */
markExpired: (id: string) => void;
/** Clear the expired flag (used after restore-with-summary succeeds). */
clearExpired: (id: string) => void;
/** Atomically swap a session's id in the list + both localStorage caches.
* Used when we rehydrate an expired session into a freshly-created backend
* session — preserves title, timestamps, and messages. */
renameSession: (oldId: string, newId: string) => void;
}
export const useSessionStore = create<SessionStore>()(
persist(
(set, get) => ({
sessions: [],
activeSessionId: null,
createSession: (id: string) => {
const newSession: SessionMeta = {
id,
title: `Chat ${get().sessions.length + 1}`,
createdAt: new Date().toISOString(),
isActive: true,
needsAttention: false,
};
set((state) => ({
sessions: [...state.sessions, newSession],
activeSessionId: id,
}));
},
deleteSession: (id: string) => {
deleteMessages(id);
deleteBackendMessages(id);
set((state) => {
const newSessions = state.sessions.filter((s) => s.id !== id);
const newActiveId =
state.activeSessionId === id
? newSessions[newSessions.length - 1]?.id || null
: state.activeSessionId;
return {
sessions: newSessions,
activeSessionId: newActiveId,
};
});
},
markExpired: (id: string) => {
set((state) => ({
sessions: state.sessions.map((s) => (s.id === id ? { ...s, expired: true } : s)),
}));
},
clearExpired: (id: string) => {
set((state) => ({
sessions: state.sessions.map((s) =>
s.id === id ? { ...s, expired: false } : s,
),
}));
},
renameSession: (oldId: string, newId: string) => {
if (oldId === newId) return;
moveMessages(oldId, newId);
moveBackendMessages(oldId, newId);
set((state) => ({
sessions: state.sessions.map((s) =>
s.id === oldId ? { ...s, id: newId, expired: false } : s,
),
activeSessionId: state.activeSessionId === oldId ? newId : state.activeSessionId,
}));
},
switchSession: (id: string) => {
set((state) => ({
activeSessionId: id,
sessions: state.sessions.map((s) =>
s.id === id ? { ...s, needsAttention: false } : s
),
}));
},
setSessionActive: (id: string, isActive: boolean) => {
set((state) => ({
sessions: state.sessions.map((s) =>
s.id === id ? { ...s, isActive } : s
),
}));
},
updateSessionTitle: (id: string, title: string) => {
set((state) => ({
sessions: state.sessions.map((s) =>
s.id === id ? { ...s, title } : s
),
}));
},
setNeedsAttention: (id: string, needs: boolean) => {
set((state) => ({
sessions: state.sessions.map((s) =>
s.id === id ? { ...s, needsAttention: needs } : s
),
}));
},
}),
{
name: 'hf-agent-sessions',
partialize: (state) => ({
sessions: state.sessions,
activeSessionId: state.activeSessionId,
}),
}
)
);
|