1- import { useEffect , useCallback , useState } from 'react'
1+ import { useEffect , useCallback , useState , useRef } from 'react'
22import { MessageType } from '@/lib/types/messaging'
33import { useSidePanelPortMessaging } from '@/sidepanel/hooks'
44import { useChatStore , type PubSubMessage } from '../stores/chatStore'
@@ -9,9 +9,16 @@ interface HumanInputRequest {
99}
1010
1111export function useMessageHandler ( ) {
12- const { upsertMessage, setProcessing } = useChatStore ( )
13- const { addMessageListener, removeMessageListener, executionId } = useSidePanelPortMessaging ( )
12+ const { upsertMessage, setProcessing, reset } = useChatStore ( )
13+ const { addMessageListener, removeMessageListener, executionId, sendMessage } = useSidePanelPortMessaging ( )
1414 const [ humanInputRequest , setHumanInputRequest ] = useState < HumanInputRequest | null > ( null )
15+ const reconnectCallbackRef = useRef < ( ( executionId : string ) => void ) | null > ( null )
16+
17+ // Keep executionId in a ref to always have the current value
18+ const executionIdRef = useRef < string | null > ( executionId )
19+ useEffect ( ( ) => {
20+ executionIdRef . current = executionId
21+ } , [ executionId ] )
1522
1623 const clearHumanInputRequest = useCallback ( ( ) => {
1724 setHumanInputRequest ( null )
@@ -70,8 +77,8 @@ export function useMessageHandler() {
7077
7178 // Handle workflow status for processing state
7279 const handleWorkflowStatus = useCallback ( ( payload : any ) => {
73- // Check if this is for our execution
74- if ( payload ?. executionId && payload . executionId !== executionId ) {
80+ // Check if this is for our execution using ref for current value
81+ if ( payload ?. executionId && payload . executionId !== executionIdRef . current ) {
7582 return // Ignore messages for other executions
7683 }
7784
@@ -81,22 +88,62 @@ export function useMessageHandler() {
8188 }
8289 // Note: We still let ChatInput set processing(true) when sending query
8390 // This avoids race conditions and provides immediate UI feedback
84- } , [ executionId , setProcessing ] )
91+ } , [ setProcessing ] )
8592
8693 useEffect ( ( ) => {
8794 // Register listeners
8895 addMessageListener ( MessageType . AGENT_STREAM_UPDATE , handleStreamUpdate )
8996 addMessageListener ( MessageType . WORKFLOW_STATUS , handleWorkflowStatus )
9097
98+ // Listen for context switch messages from background
99+ const handleRuntimeMessage = ( message : any ) => {
100+ if ( message ?. type === MessageType . SWITCH_EXECUTION_CONTEXT ) {
101+ const { executionId : newExecutionId , tabId, cancelExisting } = message . payload
102+
103+ console . log ( `[SidePanel] Received SWITCH_EXECUTION_CONTEXT: ${ newExecutionId } , current: ${ executionIdRef . current } ` )
104+
105+ // Only switch if it's a different execution (use ref for current value)
106+ if ( newExecutionId !== executionIdRef . current ) {
107+ // If we should cancel and reset existing
108+ if ( cancelExisting ) {
109+ // Cancel any existing task
110+ sendMessage ( MessageType . RESET_CONVERSATION , {
111+ reason : 'New task started from NewTab' ,
112+ source : 'sidepanel'
113+ } )
114+
115+ setProcessing ( false )
116+ reset ( )
117+ }
118+
119+ // Trigger reconnection with new executionId
120+ if ( reconnectCallbackRef . current ) {
121+ reconnectCallbackRef . current ( newExecutionId )
122+ }
123+ } else {
124+ console . log ( `[SidePanel] Same executionId, no need to switch` )
125+ }
126+ }
127+ }
128+
129+ chrome . runtime . onMessage . addListener ( handleRuntimeMessage )
130+
91131 // Cleanup
92132 return ( ) => {
93133 removeMessageListener ( MessageType . AGENT_STREAM_UPDATE , handleStreamUpdate )
94134 removeMessageListener ( MessageType . WORKFLOW_STATUS , handleWorkflowStatus )
135+ chrome . runtime . onMessage . removeListener ( handleRuntimeMessage )
95136 }
96- } , [ addMessageListener , removeMessageListener , handleStreamUpdate , handleWorkflowStatus ] )
137+ } , [ addMessageListener , removeMessageListener , handleStreamUpdate , handleWorkflowStatus , sendMessage , reset , setProcessing ] )
138+
139+ // Set the reconnect callback that will be triggered on context switch
140+ const setReconnectCallback = useCallback ( ( callback : ( executionId : string ) => void ) => {
141+ reconnectCallbackRef . current = callback
142+ } , [ ] )
97143
98144 return {
99145 humanInputRequest,
100- clearHumanInputRequest
146+ clearHumanInputRequest,
147+ setReconnectCallback
101148 }
102149}
0 commit comments