feat: store working directory for sessions (#1559)
This commit is contained in:
@@ -48,63 +48,28 @@ export default function ChatView({
|
||||
const resumedSession = viewOptions?.resumedSession;
|
||||
|
||||
// Generate or retrieve session ID
|
||||
const [sessionId] = useState(() => {
|
||||
// If resuming a session, use that session ID
|
||||
if (resumedSession?.session_id) {
|
||||
// Store the resumed session ID in sessionStorage
|
||||
window.sessionStorage.setItem('goose-session-id', resumedSession.session_id);
|
||||
return resumedSession.session_id;
|
||||
}
|
||||
|
||||
// For a new chat, generate a new session ID
|
||||
const newId = generateSessionId();
|
||||
window.sessionStorage.setItem('goose-session-id', newId);
|
||||
return newId;
|
||||
});
|
||||
// The session ID should not change for the duration of the chat
|
||||
const sessionId = resumedSession?.session_id || generateSessionId();
|
||||
|
||||
const [chat, setChat] = useState<ChatType>(() => {
|
||||
// If resuming a session, convert the session messages to our format
|
||||
if (resumedSession) {
|
||||
try {
|
||||
// Convert the resumed session messages to the expected format
|
||||
const convertedMessages = resumedSession.messages.map((msg): Message => {
|
||||
return {
|
||||
id: `${msg.role}-${msg.created}`,
|
||||
role: msg.role,
|
||||
created: msg.created,
|
||||
content: msg.content,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
id: Date.now(),
|
||||
title: resumedSession.metadata?.description || `ID: ${resumedSession.session_id}`,
|
||||
messageHistoryIndex: convertedMessages.length,
|
||||
messages: convertedMessages,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('Failed to parse resumed session:', e);
|
||||
}
|
||||
return {
|
||||
id: resumedSession.session_id,
|
||||
title: resumedSession.metadata?.description || `ID: ${resumedSession.session_id}`,
|
||||
messages: resumedSession.messages,
|
||||
messageHistoryIndex: resumedSession.messages.length,
|
||||
};
|
||||
}
|
||||
|
||||
// Try to load saved chat from sessionStorage
|
||||
const savedChat = window.sessionStorage.getItem(`goose-chat-${sessionId}`);
|
||||
if (savedChat) {
|
||||
try {
|
||||
return JSON.parse(savedChat);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse saved chat:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Return default chat if no saved chat exists
|
||||
return {
|
||||
id: Date.now(),
|
||||
title: 'Chat 1',
|
||||
id: sessionId,
|
||||
title: 'New Chat',
|
||||
messages: [],
|
||||
messageHistoryIndex: 0,
|
||||
};
|
||||
});
|
||||
|
||||
const [messageMetadata, setMessageMetadata] = useState<Record<string, string[]>>({});
|
||||
const [hasMessages, setHasMessages] = useState(false);
|
||||
const [lastInteractionTime, setLastInteractionTime] = useState<number>(Date.now());
|
||||
@@ -124,8 +89,8 @@ export default function ChatView({
|
||||
handleSubmit: _submitMessage,
|
||||
} = useMessageStream({
|
||||
api: getApiUrl('/reply'),
|
||||
initialMessages: chat?.messages || [],
|
||||
body: { session_id: sessionId },
|
||||
initialMessages: resumedSession ? resumedSession.messages : chat?.messages || [],
|
||||
body: { session_id: sessionId, session_working_dir: window.appConfig.get('GOOSE_WORKING_DIR') },
|
||||
onFinish: async (message, _reason) => {
|
||||
window.electron.stopPowerSaveBlocker();
|
||||
|
||||
@@ -155,15 +120,9 @@ export default function ChatView({
|
||||
useEffect(() => {
|
||||
setChat((prevChat) => {
|
||||
const updatedChat = { ...prevChat, messages };
|
||||
// Save to sessionStorage
|
||||
try {
|
||||
window.sessionStorage.setItem(`goose-chat-${sessionId}`, JSON.stringify(updatedChat));
|
||||
} catch (e) {
|
||||
console.error('Failed to save chat to sessionStorage:', e);
|
||||
}
|
||||
return updatedChat;
|
||||
});
|
||||
}, [messages, sessionId]);
|
||||
}, [messages, sessionId, resumedSession]);
|
||||
|
||||
useEffect(() => {
|
||||
if (messages.length > 0) {
|
||||
|
||||
@@ -247,7 +247,10 @@ export default function MoreMenu({
|
||||
<button
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
window.electron.createChatWindow();
|
||||
window.electron.createChatWindow(
|
||||
undefined,
|
||||
window.appConfig.get('GOOSE_WORKING_DIR')
|
||||
);
|
||||
}}
|
||||
className="w-full text-left p-2 text-sm hover:bg-bgSubtle transition-colors"
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Clock, MessageSquare, ArrowLeft, AlertCircle } from 'lucide-react';
|
||||
import { Clock, MessageSquare, Folder, AlertCircle } from 'lucide-react';
|
||||
import { type SessionDetails } from '../../sessions';
|
||||
import { Card } from '../ui/card';
|
||||
import { Button } from '../ui/button';
|
||||
@@ -69,6 +69,10 @@ const SessionHistoryView: React.FC<SessionHistoryViewProps> = ({
|
||||
<Clock className="w-4 h-4 mr-1" />
|
||||
{new Date(session.messages[0]?.created * 1000).toLocaleString()}
|
||||
</span>
|
||||
<span className="flex items-center">
|
||||
<Folder className="w-4 h-4 mr-1" />
|
||||
{session.metadata.working_dir}
|
||||
</span>
|
||||
<span className="flex items-center">
|
||||
<MessageSquare className="w-4 h-4 mr-1" />
|
||||
{session.metadata.message_count} messages
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ViewConfig } from '../../App';
|
||||
import { MessageSquare, Loader, AlertCircle, Calendar, ChevronRight } from 'lucide-react';
|
||||
import { MessageSquare, Loader, AlertCircle, Calendar, ChevronRight, Folder } from 'lucide-react';
|
||||
import { fetchSessions, type Session } from '../../sessions';
|
||||
import { Card } from '../ui/card';
|
||||
import { Button } from '../ui/button';
|
||||
@@ -104,9 +104,15 @@ const SessionListView: React.FC<SessionListViewProps> = ({ setView, onSelectSess
|
||||
<h3 className="text-base font-medium text-textStandard truncate">
|
||||
{session.metadata.description || session.id}
|
||||
</h3>
|
||||
<div className="flex items-center mt-1 text-textSubtle text-sm">
|
||||
<Calendar className="w-3 h-3 mr-1 flex-shrink-0" />
|
||||
<span className="truncate">{formatDate(session.modified)}</span>
|
||||
<div className="flex gap-3">
|
||||
<div className="flex items-center text-textSubtle text-sm">
|
||||
<Calendar className="w-3 h-3 mr-1 flex-shrink-0" />
|
||||
<span className="truncate">{formatDate(session.modified)}</span>
|
||||
</div>
|
||||
<div className="flex items-center text-textSubtle text-sm">
|
||||
<Folder className="w-3 h-3 mr-1 flex-shrink-0" />
|
||||
<span className="truncate">{session.metadata.working_dir}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -40,10 +40,26 @@ const SessionsView: React.FC<SessionsViewProps> = ({ setView }) => {
|
||||
|
||||
const handleResumeSession = () => {
|
||||
if (selectedSession) {
|
||||
// Pass the session to ChatView for resuming
|
||||
setView('chat', {
|
||||
resumedSession: selectedSession,
|
||||
});
|
||||
// Get the working directory from the session metadata
|
||||
const workingDir = selectedSession.metadata.working_dir;
|
||||
|
||||
if (workingDir) {
|
||||
console.log(
|
||||
`Resuming session with ID: ${selectedSession.session_id}, in working dir: ${workingDir}`
|
||||
);
|
||||
|
||||
// Create a new chat window with the working directory and session ID
|
||||
window.electron.createChatWindow(
|
||||
undefined,
|
||||
workingDir,
|
||||
undefined,
|
||||
selectedSession.session_id
|
||||
);
|
||||
} else {
|
||||
// Fallback if no working directory is found
|
||||
console.error('No working directory found in session metadata');
|
||||
// We could show a toast or alert here
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user