saved sessions: replace transient history with persistent DB storage and auto-save

- Add saved_sessions table and CRUD endpoints (save, list, resume, update, delete)
- Save is instant (no LLM summarization), stores exact conversation with tool calls
- Resume loads full message history into chat UI, sends transcript to agent on first message
- Auto-save updates DB after every agent response once a session is saved
- Delete old filesystem-based session/group management (sessions router, useChatSessions, useChatGroups)
- Clean up ChatHeader, SessionList, ChatDetailPanel for saved sessions flow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 13:36:25 +00:00
co-authored by Claude Opus 4.6
parent d88fe3cac7
commit 2a8df0def1
39 changed files with 3272 additions and 2257 deletions
@@ -5,7 +5,6 @@ import { WorkspaceView } from 'officerdev';
import { useIsMobile } from 'hooks/useIsMobile';
import { useDashboardState } from 'state/useDashboardState';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { useChatSessions } from 'state/useChatSessions';
import { defaultLayout } from './defaultLayout';
export { ChatHistory as ChatHistoryApp } from './Widget';
@@ -35,7 +34,6 @@ type SessionListPageProps = {
export const SessionListPage = ({ isNew }: SessionListPageProps) => {
const { sessionId } = useParams<{ sessionId: string }>();
const { sessions } = useChatSessions();
const [, setSelected] = usePanelChannel<SelectedSession>('chat:selected-session', null);
const rawWorkspace = useDashboardState<LayoutNode>('screens/chat', defaultLayout);
const isMobile = useIsMobile();
@@ -62,8 +60,7 @@ export const SessionListPage = ({ isNew }: SessionListPageProps) => {
return;
}
if (!sessionId) return;
const session = sessions.find((s) => s.id === sessionId);
setSelected({ id: sessionId, model: session?.model ?? null });
setSelected({ id: sessionId });
}, [sessionId, isNew]);
return (