Align Assistant prompt history recall

This commit is contained in:
rcourtman
2026-06-06 03:48:47 +01:00
parent a7854bf341
commit 409cc9b836
3 changed files with 16 additions and 5 deletions
@@ -123,8 +123,14 @@ runtime cost control, and shared AI transport surfaces.
may persist a bounded local history of submitted prompt text and structured
mentions for ArrowUp/ArrowDown recall, but that history must not persist or
replay one-shot finding handoff, approval, autonomous-mode, or other scoped
send options. Scoped context replay remains owned by explicit session
handoff metadata or queued follow-up edit state.
send options. The referenced OpenCode source at fetched `origin/dev` commit
`ba57718b0516c7a8670d1e820b1a24146a8b8262` binds prompt history navigation
in `packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx` to the
input cursor boundary: previous history is available at the start of the
current draft, and next history restores the saved draft at the end. Pulse's
Assistant drawer follows that draft-safe recall model rather than limiting
history recall to an empty composer. Scoped context replay remains owned by
explicit session handoff metadata or queued follow-up edit state.
Failed-turn retry is part of that same local chat-runtime boundary: a
retryable in-memory assistant error may replay the original user turn's
structured mentions, finding id, approval override, handoff resources,
@@ -1332,7 +1332,7 @@ describe('AIChat', () => {
await waitFor(() => expect(textarea.value).toBe(''));
});
it('does not replace a non-empty composer draft with prompt history', () => {
it('recalls prompt history from the start of a draft and restores the draft', async () => {
localStorage.setItem(
'pulse:ai_chat_prompt_history',
JSON.stringify([{ prompt: 'previous prompt', mentions: [] }]),
@@ -1344,9 +1344,14 @@ describe('AIChat', () => {
) as HTMLTextAreaElement;
fireEvent.input(textarea, { target: { value: 'draft prompt' } });
textarea.setSelectionRange(0, 0);
fireEvent.keyDown(textarea, { key: 'ArrowUp' });
expect(textarea.value).toBe('draft prompt');
await waitFor(() => expect(textarea.value).toBe('previous prompt'));
fireEvent.keyDown(textarea, { key: 'ArrowDown' });
await waitFor(() => expect(textarea.value).toBe('draft prompt'));
});
it('loads persisted prompt history for recall', async () => {
@@ -592,7 +592,7 @@ export const AIChat: Component<AIChatProps> = (props) => {
const cursor = textareaRef.selectionStart ?? text.length;
const inHistory = promptHistoryIndex() >= 0;
if (inHistory) return cursor === 0 || cursor === text.length;
if (direction === 'up') return cursor === 0 && text.length === 0;
if (direction === 'up') return cursor === 0;
return false;
};