Skip to content

Conversation

@hannesrudolph
Copy link
Collaborator

@hannesrudolph hannesrudolph commented Jun 8, 2025

Fixes #4139

Description

This PR implements hybrid prompt history navigation using arrow up/down keys in the chat input field, providing an intuitive
terminal-like experience that adapts to the user's current context.

Key Features

Hybrid Navigation Sources

  • Active conversation: Navigate through recent conversation messages (newest first)
  • Starting fresh: Navigate through task history from previous sessions (newest first)

Smart Context Detection

  • Automatically detects if user is in an active conversation vs starting fresh
  • Seamlessly switches between clineMessages and taskHistory as data sources
  • Resets navigation position when switching between history sources

Terminal-like UX

  • Arrow Up: Navigate to previous (older) prompts
  • Arrow Down: Navigate to next (newer) prompts or return to current input
  • Only triggers when cursor is at first/last line of textarea
  • Preserves current input when starting navigation
  • Restores current input when navigating back to present

Performance & Memory Management

  • 100-item history limit to prevent memory issues
  • Efficient filtering of empty/whitespace-only messages
  • Workspace-aware filtering for task history

Navigation Behavior

  1. In Active Conversation:

    • Press ↑ to get most recent conversation message
    • Continue ↑ to go through older conversation messages
    • Press ↓ to move forward through newer messages
  2. Starting Fresh (No Active Conversation):

    • Press ↑ to get most recent task from history
    • Continue ↑ to go through older tasks
    • Press ↓ to move forward through newer tasks
  3. Edge Cases:

    • Empty conversation history: Navigation does nothing
    • Single prompt with no follow-ups: No navigation (fixed in latest commit)
    • Typing while navigating: Automatically resets navigation state

Technical Implementation

  • Custom usePromptHistory hook encapsulates all navigation logic
  • Cursor position management for proper UX after navigation
  • Comprehensive test coverage for all navigation scenarios
  • Integration with existing chat component without breaking changes

- Navigate through prompt history using arrow up/down keys
- Only triggers when cursor is at first line (up) or last line (down)
- Preserves current input when starting navigation
- Resets navigation state when typing or sending messages
- Follows VSCode's standard UX patterns for history navigation
@hannesrudolph hannesrudolph requested review from cte, jr and mrubens as code owners June 8, 2025 01:35
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. UI/UX UI/UX related or focused labels Jun 8, 2025
@hannesrudolph hannesrudolph marked this pull request as draft June 8, 2025 01:36
@hannesrudolph
Copy link
Collaborator Author

fixing issue where the history was inthe wrong order an it was also pulling from the pool of all history instead of just the workspace.

- Remove reverse() to maintain chronological order in history array
- Add workspace filtering to only show prompts from current workspace
- Ensure arrow up navigates to older prompts (as expected)
- Filter history items by workspace field matching current cwd
@hannesrudolph hannesrudolph marked this pull request as ready for review June 8, 2025 01:47
@hannesrudolph
Copy link
Collaborator Author

The test fail because windows is the problem :P

@hannesrudolph hannesrudolph moved this from Triage to PR [Needs Prelim Review] in Roo Code Roadmap Jun 8, 2025
@mochiya98
Copy link

Thanks, it looks good!
There might be issues with setTimeout(..., 0); depending on the update timing, so it might be better to trigger it within useLayoutEffect .
However, since this affects state management more broadly, the implementation might be a bit more complex.

const [inputValue, setInputValue] = useState<{
  value: string;
  afterRender?: "SET_CURSOR_FIRST_LINE" | "SET_CURSOR_LAST_LINE";
}>({
  value: "",
});
useLayoutEffect(() => {
  if (!inputValue.afterRender) return;
  if (inputValue.afterRender === "SET_CURSOR_FIRST_LINE") {
    if (textAreaRef.current) {
      textAreaRef.current.setSelectionRange(0, 0);
    }
  } else if (inputValue.afterRender === "SET_CURSOR_LAST_LINE") {
    if (textAreaRef.current) {
      const lines = historicalPrompt.split("\n");
      const lastLineStart =
        historicalPrompt.length - lines[lines.length - 1].length;
      textAreaRef.current.setSelectionRange(lastLineStart, lastLineStart);
    }
  }
  setInputValue(({ value }) => ({ value }));
}, [inputValue]);

// Usage
setInputValue({
  value: "...",
  afterRender: "SET_CURSOR_FIRST_LINE",
});
setInputValue({
  value: "...",
  afterRender: "SET_CURSOR_LAST_LINE",
});

- Add missing taskHistory and cwd properties to all useExtensionState mocks
- Add comprehensive test coverage for prompt history navigation feature
- Ensure all 25 tests pass including new prompt history functionality

Fixes failing Windows CI test in PR #4450
- Replace setTimeout(..., 0) with useLayoutEffect for more reliable cursor positioning
- Implement state-based cursor positioning pattern suggested by @mochiya98
- Add CursorPositionState interface for better type safety
- Maintain all existing functionality while improving timing reliability

This addresses the technical suggestion in PR #4450 comment about using
useLayoutEffect instead of setTimeout for DOM manipulation timing.
Copy link
Member

@daniel-lxs daniel-lxs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @hannesrudolph, I left some minor performance improvements suggestions.

@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Changes Requested] in Roo Code Roadmap Jun 9, 2025
…y management

- Add useMemo for prompt history filtering to prevent unnecessary re-computations
- Implement MAX_PROMPT_HISTORY_SIZE = 100 limit for memory management
- Extract logic into usePromptHistory custom hook for better code organization
- Simplify ChatTextArea component by delegating history logic to custom hook

Addresses review feedback on PR #4450 for issue #4139
- Remove unused CursorPositionState interface from ChatTextArea
- Remove unused destructured variables from usePromptHistory hook
- Fix missing dependency in useEffect dependency array
- Rename unused parameter with underscore prefix

Related to #4139
@daniel-lxs daniel-lxs moved this from PR [Changes Requested] to PR [Needs Prelim Review] in Roo Code Roadmap Jun 9, 2025
@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Changes Requested] in Roo Code Roadmap Jun 10, 2025
- In chat: Use conversation messages (user_feedback), newest first
- Out of chat: Use task history, oldest first
- Reset navigation position when switching between history sources
- Switch from taskHistory to clineMessages for active conversations
- Maintain backward compatibility with task history fallback
- Add comprehensive tests for hybrid behavior and position reset

This provides intuitive UX where:
- Users navigate recent conversation messages during tasks (newest first)
- Users access initial task prompts when starting fresh (oldest first)
- Navigation always starts fresh when switching contexts
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jun 11, 2025
@hannesrudolph hannesrudolph moved this from PR [Changes Requested] to PR [Needs Prelim Review] in Roo Code Roadmap Jun 11, 2025
@hannesrudolph hannesrudolph self-assigned this Jun 11, 2025
hannesrudolph and others added 3 commits June 11, 2025 16:29
Task history was using .slice(-100) which gets the newest 100 tasks,
but we want to show oldest tasks first when navigating. Changed to
.slice(0, 100) to get the oldest 100 tasks instead.

This ensures that when starting fresh (no conversation), up arrow
shows the oldest task prompts first, which is the intended behavior.
Copy link
Member

@daniel-lxs daniel-lxs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested it and works quite well, pressing up outside a task brings up the newest task. Pressing up inside the task brings up the newest message sent by the user.

LGTM

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Jun 11, 2025
@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Needs Review] in Roo Code Roadmap Jun 11, 2025
@mrubens
Copy link
Collaborator

mrubens commented Jun 12, 2025

It feels unintuitive to me that the up arrow within a task can also bring up messages from other tasks. Is that part of this necessary, or could we just restrict it to navigating through prompts in the current task?

@hannesrudolph
Copy link
Collaborator Author

hannesrudolph commented Jun 12, 2025

It feels unintuitive to me that the up arrow within a task can also bring up messages from other tasks. Is that part of this necessary, or could we just restrict it to navigating through prompts in the current task?

It should be restrcited to just the current task already

@hannesrudolph
Copy link
Collaborator Author

hannesrudolph commented Jun 12, 2025

It feels unintuitive to me that the up arrow within a task can also bring up messages from other tasks. Is that part of this necessary, or could we just restrict it to navigating through prompts in the current task?

Seems to be pulling up the Starting Fresh (No Active Conversation): behaviour when there is only the initial prompt in the task and no followup user messages.

…rsation

When an active task has only an initial prompt with no follow-up user messages,
the prompt history should return empty instead of falling back to task history.
This fixes the "Starting Fresh" behavior appearing inappropriately.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link
Member

@daniel-lxs daniel-lxs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit cc7bab0 solved the issue for me.

Looks good.

@hannesrudolph
Copy link
Collaborator Author

ok @mrubens try it now!

@hannesrudolph
Copy link
Collaborator Author

@mrubens
image

@mrubens mrubens merged commit 6947209 into main Jun 12, 2025
10 checks passed
@mrubens mrubens deleted the feat/issue-4139-prompt-history-navigation branch June 12, 2025 15:43
@github-project-automation github-project-automation bot moved this from PR [Needs Review] to Done in Roo Code Roadmap Jun 12, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Jun 12, 2025
@fabb
Copy link

fabb commented Jun 13, 2025

there is a problem with the implementation when the prompt is multi line: it is no longer possible to navigate between lines in the current prompt with arrow up/down.

as i wrote in my feature proposal, it should work as other native search fields in vscode that support multiple lines:

If the current field contains multiple lines, then the cursor must be in the first line when pressing arrow up to replace the text with the previous value in history. The cursor stays in the first line in that case. Arrow up can be pressed multiple times to go back in history. Arrow down goes forward in history, but again, only when the cursor is in the last line. The cursor stays in the last line in that case.

cte pushed a commit that referenced this pull request Jun 24, 2025
… (#4450)

* feat: add prompt history navigation with arrow keys (#4139)

- Navigate through prompt history using arrow up/down keys
- Only triggers when cursor is at first line (up) or last line (down)
- Preserves current input when starting navigation
- Resets navigation state when typing or sending messages
- Follows VSCode's standard UX patterns for history navigation

* fix: correct prompt history order and add workspace filtering (#4139)

- Remove reverse() to maintain chronological order in history array
- Add workspace filtering to only show prompts from current workspace
- Ensure arrow up navigates to older prompts (as expected)
- Filter history items by workspace field matching current cwd

* test: Fix Windows unit test failures for prompt history navigation

- Add missing taskHistory and cwd properties to all useExtensionState mocks
- Add comprehensive test coverage for prompt history navigation feature
- Ensure all 25 tests pass including new prompt history functionality

Fixes failing Windows CI test in PR #4450

* refactor: Improve cursor positioning with useLayoutEffect

- Replace setTimeout(..., 0) with useLayoutEffect for more reliable cursor positioning
- Implement state-based cursor positioning pattern suggested by @mochiya98
- Add CursorPositionState interface for better type safety
- Maintain all existing functionality while improving timing reliability

This addresses the technical suggestion in PR #4450 comment about using
useLayoutEffect instead of setTimeout for DOM manipulation timing.

* feat: optimize prompt history with performance improvements and memory management

- Add useMemo for prompt history filtering to prevent unnecessary re-computations
- Implement MAX_PROMPT_HISTORY_SIZE = 100 limit for memory management
- Extract logic into usePromptHistory custom hook for better code organization
- Simplify ChatTextArea component by delegating history logic to custom hook

Addresses review feedback on PR #4450 for issue #4139

* refactor: clean up unused code and fix linting issues in prompt history

- Remove unused CursorPositionState interface from ChatTextArea
- Remove unused destructured variables from usePromptHistory hook
- Fix missing dependency in useEffect dependency array
- Rename unused parameter with underscore prefix

Related to #4139

* feat: implement hybrid prompt history with position reset

- In chat: Use conversation messages (user_feedback), newest first
- Out of chat: Use task history, oldest first
- Reset navigation position when switching between history sources
- Switch from taskHistory to clineMessages for active conversations
- Maintain backward compatibility with task history fallback
- Add comprehensive tests for hybrid behavior and position reset

This provides intuitive UX where:
- Users navigate recent conversation messages during tasks (newest first)
- Users access initial task prompts when starting fresh (oldest first)
- Navigation always starts fresh when switching contexts

* fix: correct task history slicing order for prompt navigation

Task history was using .slice(-100) which gets the newest 100 tasks,
but we want to show oldest tasks first when navigating. Changed to
.slice(0, 100) to get the oldest 100 tasks instead.

This ensures that when starting fresh (no conversation), up arrow
shows the oldest task prompts first, which is the intended behavior.

* refactor: remove comment on task history size limitation and clarify order preservation

* refactor: replace local ClineMessage and TaskHistoryItem interfaces with imported types

* fix: prevent prompt history fallback to task list during active conversation

When an active task has only an initial prompt with no follow-up user messages,
the prompt history should return empty instead of falling back to task history.
This fixes the "Starting Fresh" behavior appearing inappropriately.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: Daniel Riccio <[email protected]>
Co-authored-by: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer PR - Needs Review size:XL This PR changes 500-999 lines, ignoring generated files. UI/UX UI/UX related or focused

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Navigate prompt history in prompt field via arrow up/down

6 participants