# Input History (Up/Down Arrow) ## Summary Add shell-style up/down arrow navigation through past messages in SimpleInput. History is derived from the conversation data already parsed from session logs -- no new state management, no server changes. ## How It Works Today 1. Server parses JSONL session logs, extracts user messages with `role: "user"` (`conversation.py:57-66`) 2. App.js stores parsed conversations in `conversations` state, refreshed via SSE on `conversation_mtime_ns` change 3. SessionCard receives `conversation` as a prop but does **not** pass it to SimpleInput 4. SimpleInput has no awareness of past messages ## Step 1: Pipe Conversation to SimpleInput Pass the conversation array from SessionCard into SimpleInput so it can derive history. - `SessionCard.js:165-169` -- add `conversation` prop to SimpleInput - Same for the QuestionBlock path if freeform input is used there (line 162) -- skip for now, QuestionBlock is option-based **Files**: `dashboard/components/SessionCard.js` ## Step 2: Derive User Message History Inside SimpleInput, filter conversation to user messages only. ```js const userHistory = useMemo( () => (conversation || []).filter(m => m.role === 'user').map(m => m.content), [conversation] ); ``` This updates automatically whenever the session log changes (SSE triggers conversation refresh, new prop flows down). **Files**: `dashboard/components/SimpleInput.js` ## Step 3: History Navigation State Add refs for tracking position in history and preserving the draft. ```js const historyIndexRef = useRef(-1); // -1 = not browsing const draftRef = useRef(''); // saves in-progress text before browsing ``` Use refs (not state) because index changes don't need re-renders -- only `setText` triggers the visual update. **Files**: `dashboard/components/SimpleInput.js` ## Step 4: ArrowUp/ArrowDown Keybinding In the `onKeyDown` handler (after the autocomplete block, before Enter-to-submit), add history navigation: - **ArrowUp**: only when autocomplete is closed AND cursor is at position 0 (prevents hijacking multiline cursor movement). On first press, save current text to `draftRef`. Walk backward through `userHistory`. Call `setText()` with the history entry. - **ArrowDown**: walk forward through history. If past the newest entry, restore `draftRef` and reset index to -1. - **Reset on submit**: set `historyIndexRef.current = -1` in `handleSubmit` after successful send. - **Reset on manual edit**: in `onInput`, reset `historyIndexRef.current = -1` so typing after browsing exits history mode. ### Cursor position check ```js const atStart = e.target.selectionStart === 0 && e.target.selectionEnd === 0; ``` Only intercept ArrowUp when `atStart` is true. This lets multiline text cursor movement work normally. ArrowDown can use similar logic (check if cursor is at end of text) or always navigate history when `historyIndexRef.current !== -1` (already browsing). **Files**: `dashboard/components/SimpleInput.js` ## Step 5: Modal Parity The Modal (`Modal.js:71`) also renders SimpleInput with `onRespond`. Verify it passes `conversation` through. The same SessionCard is used in enlarged mode, so this should work automatically if Step 1 is done correctly. **Files**: `dashboard/components/Modal.js` (verify, likely no change needed) ## Non-Goals - No localStorage persistence -- history comes from session logs which survive across page reloads - No server changes -- conversation parsing already extracts what we need - No new API endpoints - No changes to QuestionBlock (option-based, not free-text history) ## Test Cases | Scenario | Expected | |----------|----------| | Press up with empty input | Fills with most recent user message | | Press up multiple times | Walks backward through user messages | | Press down after browsing up | Walks forward; past newest restores draft | | Press up with text in input | Saves text as draft, shows history | | Press down past end | Restores saved draft | | Type after browsing | Exits history mode (index resets) | | Submit after browsing | Sends displayed text, resets index | | Up arrow in multiline text (cursor not at pos 0) | Normal cursor movement, no history | | New message arrives via SSE | userHistory updates, no index disruption | | Session with no prior messages | Up arrow does nothing |