Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,38 @@ describe("ChatTextArea", () => {
expect(setInputValue).toHaveBeenCalledWith("Current input")
})

it("should preserve current input while assistant messages stream", () => {
const setInputValue = vi.fn()
const { container, rerender } = render(
<ChatTextArea {...defaultProps} setInputValue={setInputValue} inputValue="Current input" />,
)
const textarea = container.querySelector("textarea")!

textarea.setSelectionRange(0, 0)
fireEvent.keyDown(textarea, { key: "ArrowUp" })
expect(setInputValue).toHaveBeenCalledWith("Third prompt")
;(useExtensionState as ReturnType<typeof vi.fn>).mockReturnValue({
filePaths: [],
openedTabs: [],
apiConfiguration: {
apiProvider: providerIdentifiers.anthropic,
},
taskHistory: [],
clineMessages: [
...mockClineMessages,
{ type: "say", say: "text", text: "Streaming assistant output", ts: 4000 },
],
cwd: "/test/workspace",
})
setInputValue.mockClear()
rerender(<ChatTextArea {...defaultProps} setInputValue={setInputValue} inputValue="Third prompt" />)
textarea.setSelectionRange(textarea.value.length, textarea.value.length)

fireEvent.keyDown(textarea, { key: "ArrowDown" })

expect(setInputValue).toHaveBeenCalledWith("Current input")
})

it("should reset history navigation when user types", () => {
const setInputValue = vi.fn()
const { container } = render(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ClineMessage, HistoryItem } from "@roo-code/types"
import { act, renderHook } from "@testing-library/react"

import { usePromptHistory } from "../usePromptHistory"

describe("usePromptHistory", () => {
it("resets navigation when switching to conversation history with identical prompts", () => {
const prompt = "Explain this code"
const taskHistory: HistoryItem[] = [
{
id: "task-1",
number: 1,
ts: 1,
task: prompt,
tokensIn: 0,
tokensOut: 0,
totalCost: 0,
workspace: "/workspace",
},
]
const conversationHistory: ClineMessage[] = [{ ts: 2, type: "say", say: "user_feedback", text: prompt }]
const setInputValue = vi.fn()

const { result, rerender } = renderHook<
ReturnType<typeof usePromptHistory>,
{ clineMessages: ClineMessage[] | undefined }
>(
({ clineMessages }) =>
usePromptHistory({
clineMessages,
taskHistory,
cwd: "/workspace",
inputValue: "draft",
setInputValue,
}),
{ initialProps: { clineMessages: undefined } },
)

act(() => {
result.current.setHistoryIndex(0)
result.current.setTempInput("draft")
})

expect(result.current.promptHistory).toEqual([prompt])
expect(result.current.historyIndex).toBe(0)
expect(result.current.tempInput).toBe("draft")

rerender({ clineMessages: conversationHistory })

expect(result.current.promptHistory).toEqual([prompt])
expect(result.current.historyIndex).toBe(-1)
expect(result.current.tempInput).toBe("")
})
})
18 changes: 15 additions & 3 deletions webview-ui/src/components/chat/hooks/usePromptHistory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ClineMessage, HistoryItem } from "@roo-code/types"
import { useCallback, useEffect, useMemo, useState } from "react"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"

interface UsePromptHistoryProps {
clineMessages: ClineMessage[] | undefined
Expand Down Expand Up @@ -38,6 +38,8 @@
const [historyIndex, setHistoryIndex] = useState(-1)
const [tempInput, setTempInput] = useState("")
const [promptHistory, setPromptHistory] = useState<string[]>([])
const historySource = clineMessages?.length ? "conversation" : "task"

Check warning on line 41 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:41: 2 mutation test gaps; example: Survived StringLiteral mutant (replacement: ""). See the job summary for the complete list and resolution guidance.
const previousHistorySource = useRef(historySource)

// Initialize prompt history with hybrid approach: conversation messages if in task, otherwise task history
const filteredPromptHistory = useMemo(() => {
Expand Down Expand Up @@ -71,11 +73,21 @@

// Update prompt history when filtered history changes and reset navigation
useEffect(() => {
setPromptHistory(filteredPromptHistory)
const historyChanged =
promptHistory.length !== filteredPromptHistory.length ||

Check warning on line 77 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:77: Survived ConditionalExpression mutant (replacement: true). See the job summary for the complete list and resolution guidance.
promptHistory.some((prompt, index) => prompt !== filteredPromptHistory[index])

Check warning on line 78 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:78: 5 mutation test gaps; example: Survived MethodExpression mutant (replacement: promptHistory.every((prompt, index) => prompt !== filteredPromptHistory[index])). See the job summary for the complete list and resolution guidance.
const historySourceChanged = previousHistorySource.current !== historySource

Check warning on line 79 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:79: Survived ConditionalExpression mutant (replacement: true). See the job summary for the complete list and resolution guidance.
previousHistorySource.current = historySource

if (!historyChanged && !historySourceChanged) return

Check warning on line 82 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:82: Survived ConditionalExpression mutant (replacement: false). See the job summary for the complete list and resolution guidance.

if (historyChanged) {

Check warning on line 84 in webview-ui/src/components/chat/hooks/usePromptHistory.ts

View workflow job for this annotation

GitHub Actions / mutation-diff

Mutation test advisory

webview-ui/src/components/chat/hooks/usePromptHistory.ts:84: Survived ConditionalExpression mutant (replacement: true). See the job summary for the complete list and resolution guidance.
setPromptHistory(filteredPromptHistory)
}
// Reset navigation state when switching between history sources
setHistoryIndex(-1)
setTempInput("")
}, [filteredPromptHistory])
}, [filteredPromptHistory, historySource, promptHistory])

// Reset history navigation when user types (but not when we're setting it programmatically)
const resetOnInputChange = useCallback(() => {
Expand Down
Loading