web assistant: one conversation, in localStorage, wiped by New chat — and only the last 8 turns reach the model
Opening this as an issue rather than a PR because it fails one of the four questions in CONTRIBUTING on its face, and I would rather hear which door it fits than send code you have to redirect. I have a working implementation, but see the routing question at the end before spending review time on it.
Current behaviour
assistant-console.tsx keeps exactly one conversation, in localStorage under career-ops:chat, capped at the last 30 messages. "New chat" calls localStorage.removeItem — the previous conversation is gone, with no list, no way back, and nothing on disk. Clearing site data loses it too.
Separately, api/assistant sends the model body.history.slice(-8). Turn nine onwards, the beginning of the conversation is simply absent from the prompt.
Both were sized for what the assistant used to be — a question box. The ONBOARDING block in the preamble now walks a new user through CV → discovery → roles → comp → location across many turns, and that is exactly the conversation that outlives 8 turns and that a user most wants back tomorrow.
Two halves, and they are separable
(a) Longer memory. For Claude, api/apply/drive.ts already demonstrates the pattern in this codebase: keep the session_id and continue with --resume, which is both cheaper than resending a transcript and not capped at 8. For CLIs without resume, the last N turns verbatim plus a one-line digest of older user turns keeps the thread without a second model call. No new file, no new user-visible surface — invisible infrastructure on the existing path, in the sense CONTRIBUTING uses.
(b) Conversations that survive. Move them out of localStorage into the gitignored user layer, with a list, switch, rename and delete; migrate the existing single conversation once. @santifer's answer on #3058 reads as the governing principle: "decisions that survive a cache clear belong in the gitignored user layer, not localStorage: that is the local-first contract."
Where the honesty is
(b) adds a new data file (a directory of them), and by question 2 of the parallel-feature test that needs demonstrated demand — issues from several people, not one — or a plugin home. Right now the demand is one person: me. I am not going to dress that up. #3058 is the same class for inbox decisions, but it is a different surface and its author has been waiting on the file-format call since 21 August, which is its own signal about how much appetite there is for adding user-layer files right now.
(a) does not add a file and is a straightforward improvement to something that already exists. If only one half of this is worth having, it is that one.
Questions
- Is (a) welcome on its own? It is small, touches only
api/assistantand the console, and needs no storage decision. - If (b) is wanted, where do the files go?
.career-ops-web/chats/sits next to the worker logs the assistant already reads, which argues for consistency with web-managed state. #3058 proposesdata/inbox-triage.json, which argues for consistency with user-layer data. Those point different directions and it should be one call, ideally the same call that unblocks #3058. - Or is (b) a plugin? Conversation history is adjacent to the job-search path rather than on it, and I would rather hear that now than after a review.
Implementation, if it is useful for judging scope: pure module for the shape and the model-context building (9 unit tests), GET/PUT/PATCH/DELETE routes, atomic writes, ids validated against one regex that also rules out traversal, a conversation written only once it holds a user message so "New chat" cannot litter the list, and a pending-save flush so switching conversations inside the debounce window cannot drop the last turn. Web suite green, tsc and production build clean. None of it is pushed anywhere public yet.
Source: santifer/career-ops