You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/chat is currently stateless: the client sends the full history array on every request (ChatRequest in src/tpk/server.py = message + history), and nothing is persisted server-side. Reloading the page or switching devices loses the conversation. Now that we have authenticated users (issue #8, merged in #9), chat history should be stored per user.
Requirements
Persistent chat history — conversations are stored server-side (a Timeplus stream), so a user's past turns survive page reloads and are retrievable across devices.
Per-user isolation — a user can only see their own conversations. No user can read, list, or resume another user's history. Enforced server-side against the authenticated identity (require_user), not just hidden in the UI.
Multiple conversations per user — a user can hold several independent conversation threads (like ChatGPT's conversation list): create a new one, list their own, open/resume one, and delete one.
Naming caveat (important)
The word "session" is already taken: kg_sessions holds auth login tokens (issue #8). To avoid collision, this feature should use a distinct term — e.g. conversation / thread — with streams like kg_conversations (metadata: id, owner username, title, created/updated) and kg_conversation_messages (conversation_id, role, content, timestamp), following the existing corpus.py/auth.py mutable-stream store pattern.
Touchpoints
src/tpk/server.py — /chat handler: associate each turn with a conversation id owned by user.username; persist the user message and the assistant's final answer. ChatRequest gains an optional conversation_id (server creates one when absent). The client can stop sending full history once the server rehydrates it from the store.
New store module (e.g. src/tpk/conversations.py) + schema in src/tpk/db.py (ensure_schema/drop_schema), mirroring auth.py.
New API routes under require_user (NOT require_admin — every user manages their own): GET /api/conversations (list mine), POST /api/conversations (new), GET /api/conversations/{id} (messages; 404 if not owned), POST /api/conversations/{id}/rename, POST /api/conversations/{id}/delete. Every handler must filter by user.username and treat another user's id as 404 (no existence leak).
Web UI: a conversation sidebar/list, new-chat button, resume-on-click, rename/delete; App.tsx chat state becomes per-conversation instead of the current single in-memory turns array.
Open questions (for design/brainstorming, not blocking the issue)
Auto-title conversations from the first message, or leave untitled until renamed?
Retention/limits (max conversations or messages per user)?
Admin visibility: per the requirement, admins do NOT get to see other users' histories through this feature (isolation is absolute); a separate audit capability would be its own issue if ever wanted.
Related: #8 (auth/users/roles, merged in #9) provides the require_user identity this builds on.
Problem
/chatis currently stateless: the client sends the fullhistoryarray on every request (ChatRequestinsrc/tpk/server.py=message+history), and nothing is persisted server-side. Reloading the page or switching devices loses the conversation. Now that we have authenticated users (issue #8, merged in #9), chat history should be stored per user.Requirements
require_user), not just hidden in the UI.Naming caveat (important)
The word "session" is already taken:
kg_sessionsholds auth login tokens (issue #8). To avoid collision, this feature should use a distinct term — e.g. conversation / thread — with streams likekg_conversations(metadata: id, owner username, title, created/updated) andkg_conversation_messages(conversation_id, role, content, timestamp), following the existingcorpus.py/auth.pymutable-stream store pattern.Touchpoints
src/tpk/server.py—/chathandler: associate each turn with a conversation id owned byuser.username; persist the user message and the assistant's final answer.ChatRequestgains an optionalconversation_id(server creates one when absent). The client can stop sending fullhistoryonce the server rehydrates it from the store.src/tpk/conversations.py) + schema insrc/tpk/db.py(ensure_schema/drop_schema), mirroringauth.py.require_user(NOTrequire_admin— every user manages their own):GET /api/conversations(list mine),POST /api/conversations(new),GET /api/conversations/{id}(messages; 404 if not owned),POST /api/conversations/{id}/rename,POST /api/conversations/{id}/delete. Every handler must filter byuser.usernameand treat another user's id as 404 (no existence leak).App.tsxchat state becomes per-conversation instead of the current single in-memoryturnsarray.Open questions (for design/brainstorming, not blocking the issue)
Related: #8 (auth/users/roles, merged in #9) provides the
require_useridentity this builds on.