diff --git a/ui/desktop/src/components/SessionPIlls.tsx b/ui/desktop/src/components/SessionPIlls.tsx deleted file mode 100644 index 647a88425..000000000 --- a/ui/desktop/src/components/SessionPIlls.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useEffect, useState } from "react" - -export default function SessionPills() { - const [sessions, setSessions] = useState([]); - const [latestSessions, setLatestSessions] = useState([]); - - const workingDir = window.appConfig.get("GOOSE_WORKING_DIR"); - - useEffect(() => { - async function loadSessions() { - window.electron.logInfo(`_------______________ Looking for sessions related to ${workingDir}`); - const sessions = await window.electron.listSessions(workingDir); - - window.electron.logInfo(`_------______________ Found ${sessions.length} sessions in ${workingDir}`); - window.electron.logInfo(`Sessions: ${JSON.stringify(sessions)}`); - setSessions(sessions); - }; - loadSessions(); - }, []); - - useEffect(() => { - async function loadSessions() { - const sessions = await window.electron.listSessions(); - setLatestSessions(sessions); - }; - loadSessions(); - }, []); - - if (sessions.length === 0 && latestSessions.length === 0) { - return null; - } - - // Create a combined list of sessions, prioritizing latest ones and removing duplicates - const combinedSessions = []; - const seenNames = new Set(); - - // Add at least one latest session if available - if (latestSessions.length > 0) { - const latest = latestSessions[0]; - combinedSessions.push({ ...latest, isLatest: true }); - seenNames.add(latest.name); - } - - // Add remaining latest sessions (up to 5 total) - for (let i = 1; i < latestSessions.length && combinedSessions.length < 5; i++) { - const session = latestSessions[i]; - if (!seenNames.has(session.name)) { - combinedSessions.push({ ...session, isLatest: true }); - seenNames.add(session.name); - } - } - - // Fill remaining slots with regular sessions (up to 5 total) - for (const session of sessions) { - if (combinedSessions.length >= 5) break; - if (!seenNames.has(session.name)) { - combinedSessions.push({ ...session, isLatest: false }); - seenNames.add(session.name); - } - } - - return ( -
-
- {combinedSessions.map((session) => ( -
{ - window.electron.createChatWindow(undefined, session.directory, session.name); - }} - title={session.directory}> - - {`${session.name.slice(0, 50)}`} - {session.isLatest && !(session.directory === workingDir) && ( - (recent) - )} -
- ))} -
-
- ) -} \ No newline at end of file diff --git a/ui/desktop/src/components/SessionPills.tsx b/ui/desktop/src/components/SessionPills.tsx new file mode 100644 index 000000000..c95eb01f9 --- /dev/null +++ b/ui/desktop/src/components/SessionPills.tsx @@ -0,0 +1,85 @@ +import React, { useEffect, useState } from "react" + +const useCombinedSessions = (workingDir: string) => { + const [sessions, setSessions] = useState([]); + const [latestSessions, setLatestSessions] = useState([]); + + useEffect(() => { + async function loadSessions() { + const sessions = await window.electron.listSessions(workingDir); + setSessions(sessions); + const latestSessions = await window.electron.listSessions(); + setLatestSessions(latestSessions); + }; + loadSessions(); + }, [workingDir]); + + const getCombinedSessions = () => { + if (sessions.length === 0 && latestSessions.length === 0) { + return []; + } + + const combinedSessions = []; + const seenNames = new Set(); + + // Add at least one latest session if available + if (latestSessions.length > 0) { + const latest = latestSessions[0]; + combinedSessions.push({ ...latest, isLatest: true }); + seenNames.add(latest.name); + } + + // Add remaining latest sessions (up to 5 total) + for (let i = 1; i < latestSessions.length && combinedSessions.length < 5; i++) { + const session = latestSessions[i]; + if (!seenNames.has(session.name)) { + combinedSessions.push({ ...session, isLatest: true }); + seenNames.add(session.name); + } + } + + // Fill remaining slots with regular sessions (up to 5 total) + for (const session of sessions) { + if (combinedSessions.length >= 5) break; + if (!seenNames.has(session.name)) { + combinedSessions.push({ ...session, isLatest: false }); + seenNames.add(session.name); + } + } + + return combinedSessions; + }; + + return getCombinedSessions(); +}; + +export default function SessionPills() { + const workingDir = window.appConfig.get("GOOSE_WORKING_DIR"); + const combinedSessions = useCombinedSessions(workingDir); + + if (combinedSessions.length === 0) { + return null; + } + + return ( +
+
+ {combinedSessions.map((session) => ( +
{ + window.electron.createChatWindow(undefined, session.directory, session.name); + }} + title={session.directory} + > + {`${session.name.slice(0, 50)}`} + {session.isLatest && !(session.directory === workingDir) && ( + (recent) + )} +
+ ))} +
+
+ ) +} \ No newline at end of file diff --git a/ui/desktop/src/components/Splash.tsx b/ui/desktop/src/components/Splash.tsx index 071081002..10dc19326 100644 --- a/ui/desktop/src/components/Splash.tsx +++ b/ui/desktop/src/components/Splash.tsx @@ -1,7 +1,7 @@ import React from 'react'; import GooseSplashLogo from './GooseSplashLogo'; import SplashPills from './SplashPills'; -import SessionPills from './SessionPIlls'; +import SessionPills from './SessionPills'; export default function Splash({ append }) { diff --git a/ui/desktop/src/utils/sessionManager.ts b/ui/desktop/src/utils/sessionManager.ts index 4572b9466..9b048ded6 100644 --- a/ui/desktop/src/utils/sessionManager.ts +++ b/ui/desktop/src/utils/sessionManager.ts @@ -4,123 +4,123 @@ import { app } from 'electron'; const SESSIONS_PATH = path.join(app.getPath('userData'), 'sessions'); if (!fs.existsSync(SESSIONS_PATH)) { - fs.mkdirSync(SESSIONS_PATH); + fs.mkdirSync(SESSIONS_PATH); } interface Session { - name: string; // Derived from a synopsis of the conversation - messages: Array<{ - id: number; - role: 'function' | 'system' | 'user' | 'assistant' | 'data' | 'tool'; - content: string; - }>; - directory: string; + name: string; // Derived from a synopsis of the conversation + messages: Array<{ + id: number; + role: 'function' | 'system' | 'user' | 'assistant' | 'data' | 'tool'; + content: string; + }>; + directory: string; } function generateSessionName(messages: {id: number, role: string, content: string}[]): string { - // Create a session name based on the first message or a combination of initial messages - if (messages === undefined || messages.length === 0) return 'empty_session'; - return messages[0].content.split(' ').slice(0, 5).join(' '); + // Create a session name based on the first message or a combination of initial messages + if (messages === undefined || messages.length === 0) return 'empty_session'; + return messages[0].content.split(' ').slice(0, 5).join(' '); } function createSafeFilename(name: string): string { - // Replace unsafe characters with underscores and limit length - return name - .replace(/[^a-zA-Z0-9-_]/g, '_') // Replace unsafe chars with underscore - .replace(/_{2,}/g, '_') // Replace multiple underscores with single - .replace(/^_|_$/g, '') // Remove leading/trailing underscores - .substring(0, 100); // Limit length to 100 chars + // Replace unsafe characters with underscores and limit length + return name + .replace(/[^a-zA-Z0-9-_]/g, '_') // Replace unsafe chars with underscore + .replace(/_{2,}/g, '_') // Replace multiple underscores with single + .replace(/^_|_$/g, '') // Remove leading/trailing underscores + .substring(0, 100); // Limit length to 100 chars } export function saveSession(session: Session): string { - try { - const sessionData = { - ...session, - name: generateSessionName(session.messages) - }; - const safeFileName = createSafeFilename(sessionData.name); - const filePath = path.join(SESSIONS_PATH, `${safeFileName}.json`); - fs.writeFileSync(filePath, JSON.stringify(sessionData, null, 2)); - console.log('Session saved:', sessionData); - return sessionData.name; - } catch (error) { - console.error('Error saving session:', error); - } + try { + const sessionData = { + ...session, + name: generateSessionName(session.messages) + }; + const safeFileName = createSafeFilename(sessionData.name); + const filePath = path.join(SESSIONS_PATH, `${safeFileName}.json`); + fs.writeFileSync(filePath, JSON.stringify(sessionData, null, 2)); + console.log('Session saved:', sessionData); + return sessionData.name; + } catch (error) { + console.error('Error saving session:', error); + } } export function loadSession(sessionId: string): Session | undefined { - try { - const safeFileName = createSafeFilename(sessionId); - const filePath = path.join(SESSIONS_PATH, `${safeFileName}.json`); - if (!fs.existsSync(filePath)) { - console.warn('Session file not found:', sessionId); - return undefined; - } - const data = fs.readFileSync(filePath, 'utf8'); - const session = JSON.parse(data) as Session; - console.log('Session loaded:', session); - return session; - } catch (error) { - console.error('Error loading session:', error); + try { + const safeFileName = createSafeFilename(sessionId); + const filePath = path.join(SESSIONS_PATH, `${safeFileName}.json`); + if (!fs.existsSync(filePath)) { + console.warn('Session file not found:', sessionId); + return undefined; } + const data = fs.readFileSync(filePath, 'utf8'); + const session = JSON.parse(data) as Session; + console.log('Session loaded:', session); + return session; + } catch (error) { + console.error('Error loading session:', error); + } } // load sessions that are relevant to the directory supplied (not where they are stored, but where user is operating) export function loadSessions(dir?: string): Session[] { - try { - console.log('Attempting to load sessions from:', SESSIONS_PATH); - const MAX_AGE_DAYS = 10; - // Get the current date - const now = Date.now(); - const maxAgeMs = MAX_AGE_DAYS * 24 * 60 * 60 * 1000; + try { + console.log('Attempting to load sessions from:', SESSIONS_PATH); + const MAX_AGE_DAYS = 10; + // Get the current date + const now = Date.now(); + const maxAgeMs = MAX_AGE_DAYS * 24 * 60 * 60 * 1000; - // Get all files in the directory - const files = fs.readdirSync(SESSIONS_PATH); + // Get all files in the directory + const files = fs.readdirSync(SESSIONS_PATH); - if (files.length === 0) { - console.warn('No session files found in directory'); - return []; - } + if (files.length === 0) { + console.warn('No session files found in directory'); + return []; + } - // Filter files based on their age and limit to max 100 files - const filteredFiles = files - .map(file => { - const filePath = path.join(SESSIONS_PATH, file); - const stats = fs.statSync(filePath); - const age = now - stats.mtimeMs; - return { file, age }; - }) - .filter(({ age }) => age <= maxAgeMs); + // Filter files based on their age and limit to max 100 files + const filteredFiles = files + .map(file => { + const filePath = path.join(SESSIONS_PATH, file); + const stats = fs.statSync(filePath); + const age = now - stats.mtimeMs; + return { file, age }; + }) + .filter(({ age }) => age <= maxAgeMs); - if (filteredFiles.length === 0) { - console.warn('No session files meet the age criteria'); - return []; - } + if (filteredFiles.length === 0) { + console.warn('No session files meet the age criteria'); + return []; + } - // Load the filtered files and parse them into sessions - const sessions = filteredFiles.map(({ file }) => { - const data = fs.readFileSync(path.join(SESSIONS_PATH, file), 'utf8'); - return JSON.parse(data) as Session; - }); - if (dir) { - // Filter sessions based on the directory - return sessions.filter(session => session.directory === dir).splice(0, 4); - } else { - // just recent sessions - return sessions.splice(0, 20); - } - } catch (error) { - console.error('Error loading sessions:', error); - return []; + // Load the filtered files and parse them into sessions + const sessions = filteredFiles.map(({ file }) => { + const data = fs.readFileSync(path.join(SESSIONS_PATH, file), 'utf8'); + return JSON.parse(data) as Session; + }); + if (dir) { + // Filter sessions based on the directory + return sessions.filter(session => session.directory === dir).splice(0, 4); + } else { + // just recent sessions + return sessions.splice(0, 20); } + } catch (error) { + console.error('Error loading sessions:', error); + return []; + } } export function clearAllSessions(): void { - try { - const files = fs.readdirSync(SESSIONS_PATH); - files.forEach(file => fs.unlinkSync(path.join(SESSIONS_PATH, file))); - console.log('All sessions cleared'); - } catch (error) { - console.error('Error clearing sessions:', error); - } + try { + const files = fs.readdirSync(SESSIONS_PATH); + files.forEach(file => fs.unlinkSync(path.join(SESSIONS_PATH, file))); + console.log('All sessions cleared'); + } catch (error) { + console.error('Error clearing sessions:', error); + } } \ No newline at end of file