Skip to content

Commit

Permalink
SessionPills file rename + hook
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Hancock committed Dec 4, 2024
1 parent 32c84f6 commit 7bce83a
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 174 deletions.
83 changes: 0 additions & 83 deletions ui/desktop/src/components/SessionPIlls.tsx

This file was deleted.

85 changes: 85 additions & 0 deletions ui/desktop/src/components/SessionPills.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="grid grid-cols-1 gap-4">
<div className="grid grid-cols-1 gap-4 mb-[8px]">
{combinedSessions.map((session) => (
<div
key={session.directory + session.name}
className="w-[312px] px-16 py-4 text-14 text-center text-splash-pills-text whitespace-nowrap cursor-pointer bg-prev-goose-gradient text-prev-goose-text rounded-[14px] inline-block hover:scale-[1.02] transition-all duration-150"
onClick={async () => {
window.electron.createChatWindow(undefined, session.directory, session.name);
}}
title={session.directory}
>
{`${session.name.slice(0, 50)}`}
{session.isLatest && !(session.directory === workingDir) && (
<span className="ml-2 text-10 opacity-70">(recent)</span>
)}
</div>
))}
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion ui/desktop/src/components/Splash.tsx
Original file line number Diff line number Diff line change
@@ -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 }) {

Expand Down
180 changes: 90 additions & 90 deletions ui/desktop/src/utils/sessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit 7bce83a

Please sign in to comment.