@@ -24,6 +24,7 @@ import BrowserSessionRow from "./BrowserSessionRow"
2424import ChatRow from "./ChatRow"
2525import ChatTextArea from "./ChatTextArea"
2626import TaskHeader from "./TaskHeader"
27+ import { AudioType } from "../../../../src/shared/WebviewMessage"
2728
2829interface ChatViewProps {
2930 isHidden : boolean
@@ -61,10 +62,24 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
6162 const [ showScrollToBottom , setShowScrollToBottom ] = useState ( false )
6263 const [ isAtBottom , setIsAtBottom ] = useState ( false )
6364
65+ const [ wasStreaming , setWasStreaming ] = useState < boolean > ( false )
66+ const [ hasStarted , setHasStarted ] = useState ( false )
67+
6468 // UI layout depends on the last 2 messages
6569 // (since it relies on the content of these messages, we are deep comparing. i.e. the button state after hitting button sets enableButtons to false, and this effect otherwise would have to true again even if messages didn't change
6670 const lastMessage = useMemo ( ( ) => messages . at ( - 1 ) , [ messages ] )
6771 const secondLastMessage = useMemo ( ( ) => messages . at ( - 2 ) , [ messages ] )
72+
73+ function playSound ( audioType : AudioType ) {
74+ vscode . postMessage ( { type : "playSound" , audioType } )
75+ }
76+
77+ function playSoundOnMessage ( audioType : AudioType ) {
78+ if ( hasStarted && ! isStreaming ) {
79+ playSound ( audioType )
80+ }
81+ }
82+
6883 useDeepCompareEffect ( ( ) => {
6984 // if last message is an ask, show user ask UI
7085 // if user finished a task, then start a new task with a new conversation history since in this moment that the extension is waiting for user response, the user could close the extension and the conversation history would be lost.
@@ -75,27 +90,31 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
7590 const isPartial = lastMessage . partial === true
7691 switch ( lastMessage . ask ) {
7792 case "api_req_failed" :
93+ playSoundOnMessage ( "progress_loop" )
7894 setTextAreaDisabled ( true )
7995 setClineAsk ( "api_req_failed" )
8096 setEnableButtons ( true )
8197 setPrimaryButtonText ( "Retry" )
8298 setSecondaryButtonText ( "Start New Task" )
8399 break
84100 case "mistake_limit_reached" :
101+ playSoundOnMessage ( "progress_loop" )
85102 setTextAreaDisabled ( false )
86103 setClineAsk ( "mistake_limit_reached" )
87104 setEnableButtons ( true )
88105 setPrimaryButtonText ( "Proceed Anyways" )
89106 setSecondaryButtonText ( "Start New Task" )
90107 break
91108 case "followup" :
109+ playSoundOnMessage ( "notification" )
92110 setTextAreaDisabled ( isPartial )
93111 setClineAsk ( "followup" )
94112 setEnableButtons ( isPartial )
95113 // setPrimaryButtonText(undefined)
96114 // setSecondaryButtonText(undefined)
97115 break
98116 case "tool" :
117+ playSoundOnMessage ( "notification" )
99118 setTextAreaDisabled ( isPartial )
100119 setClineAsk ( "tool" )
101120 setEnableButtons ( ! isPartial )
@@ -113,20 +132,23 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
113132 }
114133 break
115134 case "browser_action_launch" :
135+ playSoundOnMessage ( "notification" )
116136 setTextAreaDisabled ( isPartial )
117137 setClineAsk ( "browser_action_launch" )
118138 setEnableButtons ( ! isPartial )
119139 setPrimaryButtonText ( "Approve" )
120140 setSecondaryButtonText ( "Reject" )
121141 break
122142 case "command" :
143+ playSoundOnMessage ( "notification" )
123144 setTextAreaDisabled ( isPartial )
124145 setClineAsk ( "command" )
125146 setEnableButtons ( ! isPartial )
126147 setPrimaryButtonText ( "Run Command" )
127148 setSecondaryButtonText ( "Reject" )
128149 break
129150 case "command_output" :
151+ playSoundOnMessage ( "notification" )
130152 setTextAreaDisabled ( false )
131153 setClineAsk ( "command_output" )
132154 setEnableButtons ( true )
@@ -135,13 +157,15 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
135157 break
136158 case "completion_result" :
137159 // extension waiting for feedback. but we can just present a new task button
160+ playSoundOnMessage ( "celebration" )
138161 setTextAreaDisabled ( isPartial )
139162 setClineAsk ( "completion_result" )
140163 setEnableButtons ( ! isPartial )
141164 setPrimaryButtonText ( "Start New Task" )
142165 setSecondaryButtonText ( undefined )
143166 break
144167 case "resume_task" :
168+ playSoundOnMessage ( "notification" )
145169 setTextAreaDisabled ( false )
146170 setClineAsk ( "resume_task" )
147171 setEnableButtons ( true )
@@ -150,6 +174,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
150174 setDidClickCancel ( false ) // special case where we reset the cancel button state
151175 break
152176 case "resume_completed_task" :
177+ playSoundOnMessage ( "celebration" )
153178 setTextAreaDisabled ( false )
154179 setClineAsk ( "resume_completed_task" )
155180 setEnableButtons ( true )
@@ -441,6 +466,36 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
441466 return true
442467 } )
443468 } , [ modifiedMessages ] )
469+ useEffect ( ( ) => {
470+ if ( isStreaming ) {
471+ // Set to true once any request has started
472+ setHasStarted ( true )
473+ }
474+ // Only execute when isStreaming changes from true to false
475+ if ( wasStreaming && ! isStreaming && lastMessage ) {
476+ // Play appropriate sound based on lastMessage content
477+ if ( lastMessage . type === "ask" ) {
478+ switch ( lastMessage . ask ) {
479+ case "api_req_failed" :
480+ case "mistake_limit_reached" :
481+ playSound ( "progress_loop" )
482+ break
483+ case "tool" :
484+ case "followup" :
485+ case "browser_action_launch" :
486+ case "resume_task" :
487+ playSound ( "notification" )
488+ break
489+ case "completion_result" :
490+ case "resume_completed_task" :
491+ playSound ( "celebration" )
492+ break
493+ }
494+ }
495+ }
496+ // Update previous value
497+ setWasStreaming ( isStreaming )
498+ } , [ isStreaming , lastMessage ] )
444499
445500 const isBrowserSessionMessage = ( message : ClineMessage ) : boolean => {
446501 // which of visible messages are browser session messages, see above
0 commit comments