mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-08 22:21:23 +00:00
Fixes #4885: Prevent completion sound from playing when reopening completed tasks
- Added state tracking for tasks that have already played completion sound - Modified completion_result case to only play sound once per task - Removed sound from resume_completed_task case entirely - Added tests to verify the fix works correctly - Clear sound tracking when starting new tasks
This commit is contained in:
parent
2e2f83be60
commit
4b20c22051
3 changed files with 731 additions and 4 deletions
588
roo-code-messages.log
Normal file
588
roo-code-messages.log
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -97,6 +97,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
soundVolume,
|
||||
} = useExtensionState()
|
||||
|
||||
// Track which tasks have already played their completion sound
|
||||
const [completedTasksWithSound, setCompletedTasksWithSound] = useState<Set<string>>(new Set())
|
||||
|
||||
const messagesRef = useRef(messages)
|
||||
useEffect(() => {
|
||||
messagesRef.current = messages
|
||||
|
|
@ -330,7 +333,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
case "completion_result":
|
||||
// extension waiting for feedback. but we can just present a new task button
|
||||
if (!isPartial) {
|
||||
playSound("celebration")
|
||||
const taskId = task?.ts?.toString() || "unknown"
|
||||
if (!completedTasksWithSound.has(taskId)) {
|
||||
playSound("celebration")
|
||||
setCompletedTasksWithSound((prev) => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.add(taskId)
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
}
|
||||
setSendingDisabled(isPartial)
|
||||
setClineAsk("completion_result")
|
||||
|
|
@ -350,9 +361,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
setDidClickCancel(false) // special case where we reset the cancel button state
|
||||
break
|
||||
case "resume_completed_task":
|
||||
if (!isPartial) {
|
||||
playSound("celebration")
|
||||
}
|
||||
// Don't play celebration sound when reopening completed tasks from history
|
||||
// The sound should only play when the task is first completed
|
||||
setSendingDisabled(false)
|
||||
setClineAsk("resume_completed_task")
|
||||
setEnableButtons(true)
|
||||
|
|
@ -406,6 +416,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
useEffect(() => {
|
||||
setExpandedRows({})
|
||||
everVisibleMessagesTsRef.current.clear() // Clear for new task
|
||||
// Clear completed tasks sound tracking when starting a new task
|
||||
setCompletedTasksWithSound(new Set())
|
||||
}, [task?.ts])
|
||||
|
||||
useEffect(() => () => everVisibleMessagesTsRef.current.clear(), [])
|
||||
|
|
|
|||
|
|
@ -935,6 +935,133 @@ describe("ChatView - Sound Playing Tests", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it("does not play celebration sound when reopening completed tasks from history", async () => {
|
||||
renderChatView()
|
||||
|
||||
// First hydrate state with a completed task from history
|
||||
mockPostMessage({
|
||||
clineMessages: [
|
||||
{
|
||||
type: "say",
|
||||
say: "task",
|
||||
ts: Date.now() - 2000,
|
||||
text: "Initial task",
|
||||
},
|
||||
{
|
||||
type: "ask",
|
||||
ask: "completion_result",
|
||||
ts: Date.now() - 1000,
|
||||
text: "Task completed successfully",
|
||||
partial: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Clear any previous sound calls
|
||||
mockPlayFunction.mockClear()
|
||||
|
||||
// Then send the resume_completed_task message (reopening from history)
|
||||
mockPostMessage({
|
||||
clineMessages: [
|
||||
{
|
||||
type: "say",
|
||||
say: "task",
|
||||
ts: Date.now() - 2000,
|
||||
text: "Initial task",
|
||||
},
|
||||
{
|
||||
type: "ask",
|
||||
ask: "completion_result",
|
||||
ts: Date.now() - 1000,
|
||||
text: "Task completed successfully",
|
||||
partial: false,
|
||||
},
|
||||
{
|
||||
type: "ask",
|
||||
ask: "resume_completed_task",
|
||||
ts: Date.now(),
|
||||
text: "Resuming completed task",
|
||||
partial: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Wait a bit to ensure any async operations complete
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
|
||||
// Verify celebration sound was NOT played for resume_completed_task
|
||||
// (it should have been played only once for the original completion_result)
|
||||
expect(mockPlayFunction).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("plays celebration sound only once per task completion", async () => {
|
||||
renderChatView()
|
||||
|
||||
// First hydrate state with initial task
|
||||
mockPostMessage({
|
||||
clineMessages: [
|
||||
{
|
||||
type: "say",
|
||||
say: "task",
|
||||
ts: Date.now() - 2000,
|
||||
text: "Initial task",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Clear any previous sound calls
|
||||
mockPlayFunction.mockClear()
|
||||
|
||||
// Send the first completion result message
|
||||
mockPostMessage({
|
||||
clineMessages: [
|
||||
{
|
||||
type: "say",
|
||||
say: "task",
|
||||
ts: Date.now() - 2000,
|
||||
text: "Initial task",
|
||||
},
|
||||
{
|
||||
type: "ask",
|
||||
ask: "completion_result",
|
||||
ts: Date.now(),
|
||||
text: "Task completed successfully",
|
||||
partial: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Wait for the sound to be played
|
||||
await waitFor(() => {
|
||||
expect(mockPlayFunction).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
// Send the same completion result message again (simulating reopening)
|
||||
mockPostMessage({
|
||||
clineMessages: [
|
||||
{
|
||||
type: "say",
|
||||
say: "task",
|
||||
ts: Date.now() - 2000,
|
||||
text: "Initial task",
|
||||
},
|
||||
{
|
||||
type: "ask",
|
||||
ask: "completion_result",
|
||||
ts: Date.now(),
|
||||
text: "Task completed successfully",
|
||||
partial: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Wait a bit to ensure any async operations complete
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
|
||||
// Verify celebration sound was still only played once
|
||||
expect(mockPlayFunction).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("plays progress_loop sound for api failures", async () => {
|
||||
renderChatView()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue