Problem
useChat.ts initializes its messages state fresh on every component mount. All conversation history is lost on page reload, making the AI harness effectively stateless across sessions. There is no session management UI to view, switch, or clear chat sessions.
Impact
- Users lose all context when refreshing the page
- No ability to continue a previous conversation
- No audit trail of AI interactions
- Rebuilding context manually on every session wastes tokens
Proposed Implementation
1. Chat session data model
// src/lib/chat/types.ts
export interface ChatSession {
id: string;
title: string; // auto-generated from first message
messages: Message[];
createdAt: number;
updatedAt: number;
model: string;
provider: string;
}
2. IndexedDB persistence layer
// src/lib/chat/chat-persistence.ts
import { openDB } from 'idb';
const DB_NAME = 'do-knowledge-studio';
const STORE = 'chat-sessions';
export async function saveChatSession(session: ChatSession): Promise<void> {
const db = await openDB(DB_NAME, 1, {
upgrade(db) {
if (!db.objectStoreNames.contains(STORE)) {
const store = db.createObjectStore(STORE, { keyPath: 'id' });
store.createIndex('updatedAt', 'updatedAt');
}
},
});
await db.put(STORE, session);
}
export async function loadChatSessions(): Promise<ChatSession[]> {
const db = await openDB(DB_NAME, 1);
return db.getAllFromIndex(STORE, 'updatedAt');
}
export async function deleteChatSession(id: string): Promise<void> {
const db = await openDB(DB_NAME, 1);
await db.delete(STORE, id);
}
3. Update useChat.ts
// Initialize from persisted session
const [sessionId] = useState(() => currentSessionId ?? crypto.randomUUID());
// Load messages from IndexedDB on mount
useEffect(() => {
loadChatSession(sessionId).then(session => {
if (session) setMessages(session.messages);
});
}, [sessionId]);
// Auto-save on every message change (debounced 500ms)
useEffect(() => {
const timeout = setTimeout(() => {
saveChatSession({
id: sessionId,
title: messages[0]?.content.slice(0, 60) ?? 'New Chat',
messages,
createdAt: Date.now(),
updatedAt: Date.now(),
model: currentModel,
provider: currentProvider,
});
}, 500);
return () => clearTimeout(timeout);
}, [messages]);
4. Session management sidebar
Add a ChatSessionList component in AIHarness.tsx:
- Lists recent sessions (sorted by
updatedAt desc)
- Click to switch to session and load its messages
- "New Chat" button to create a fresh session
- Delete button per session with confirmation
- Session title auto-generated from first user message (first 60 chars)
- Optional: export session as Markdown
5. Session title auto-generation
function generateSessionTitle(messages: Message[]): string {
const firstUserMsg = messages.find(m => m.role === 'user');
if (!firstUserMsg) return 'New Chat';
return firstUserMsg.content.slice(0, 60) + (firstUserMsg.content.length > 60 ? '...' : '');
}
Acceptance Criteria
Problem
useChat.tsinitializes itsmessagesstate fresh on every component mount. All conversation history is lost on page reload, making the AI harness effectively stateless across sessions. There is no session management UI to view, switch, or clear chat sessions.Impact
Proposed Implementation
1. Chat session data model
2. IndexedDB persistence layer
3. Update
useChat.ts4. Session management sidebar
Add a
ChatSessionListcomponent inAIHarness.tsx:updatedAtdesc)5. Session title auto-generation
Acceptance Criteria
ChatSessiontype defined with id, title, messages, timestamps, model/providerchat-persistence.tswith IndexedDB save/load/delete usingidblibraryuseChat.tsloads from and saves to IndexedDBChatSessionListsidebar component implemented