1- import { useEffect , useRef } from "react"
1+ import { useCallback , useEffect , useRef } from "react"
22import { AgentStore } from "store"
3+ import { log } from "utils/logger"
34import { messageTypes , runAgentLoop } from "utils/runAgentLoop"
45
56export function useAgent ( ) {
67 const messageQueue = AgentStore . useStoreState ( ( state ) => state . messageQueue )
7- const sessionId = AgentStore . useStoreState ( ( state ) => state . sessionId )
88 const config = AgentStore . useStoreState ( ( state ) => state . config )
9- const abortController = AgentStore . useStoreState (
10- ( state ) => state . abortController
11- )
129 const actions = AgentStore . useStoreActions ( ( actions ) => actions )
1310 const currentAssistantMessageRef = useRef ( "" )
14- const abortControllerRef = useRef ( abortController )
11+ const sessionIdRef = useRef < string | undefined > ( undefined )
12+ const abortControllerRef = useRef < AbortController | undefined > ( undefined )
13+ const connectedServersRef = useRef < Set < string > > ( new Set ( ) )
1514
16- // Update ref when abort controller changes
17- abortControllerRef . current = abortController
15+ const runQuery = useCallback (
16+ async ( userMessage : string ) => {
17+ if ( abortControllerRef . current ) {
18+ log ( "[useAgent] Aborting existing query for new message:" , userMessage )
1819
19- useEffect ( ( ) => {
20- const streamEnabled = config . stream ?? false
21-
22- const runAgent = async ( ) => {
23- const { agentLoop } = await runAgentLoop ( {
24- messageQueue,
25- sessionId,
26- config,
27- abortControllerRef,
28- onToolPermissionRequest : ( toolName , input ) => {
29- actions . setPendingToolPermission ( { toolName, input } )
30- } ,
31- onServerConnection : ( status ) => {
32- actions . addChatHistoryEntry ( {
33- type : "message" ,
34- role : "system" ,
35- content : status ,
36- } )
37- } ,
38- setIsProcessing : actions . setIsProcessing ,
39- } )
20+ // When a new message comes in, always abort the old one and start fresh
21+ abortControllerRef . current . abort ( )
22+ }
23+
24+ // Create fresh abort controller for this query
25+ const abortController = new AbortController ( )
26+ abortControllerRef . current = abortController
27+ actions . setAbortController ( abortController )
28+
29+ const streamEnabled = config . stream ?? false
4030
4131 try {
32+ const agentLoop = runAgentLoop ( {
33+ abortController,
34+ config,
35+ connectedServers : connectedServersRef . current ,
36+ messageQueue,
37+ onToolPermissionRequest : ( toolName , input ) => {
38+ actions . setPendingToolPermission ( { toolName, input } )
39+ } ,
40+ onServerConnection : ( status ) => {
41+ actions . addChatHistoryEntry ( {
42+ type : "message" ,
43+ role : "system" ,
44+ content : status ,
45+ } )
46+ } ,
47+ sessionId : sessionIdRef . current ,
48+ setIsProcessing : actions . setIsProcessing ,
49+ userMessage,
50+ } )
51+
4252 for await ( const message of agentLoop ) {
53+ if ( abortController . signal . aborted ) {
54+ log ( "[useAgent] Query was aborted, stopping message processing" )
55+ return
56+ }
57+
4358 switch ( true ) {
4459 case message . type === messageTypes . SYSTEM &&
4560 message . subtype === messageTypes . INIT : {
61+ sessionIdRef . current = message . session_id
4662 actions . setSessionId ( message . session_id )
4763 actions . handleMcpServerStatus ( message . mcp_servers )
4864
@@ -127,6 +143,12 @@ export function useAgent() {
127143 }
128144 }
129145 } catch ( error ) {
146+ if ( error instanceof Error && error . name === "AbortError" ) {
147+ actions . setIsProcessing ( false )
148+ return
149+ }
150+
151+ // Handle other errors
130152 if (
131153 error instanceof Error &&
132154 ! error . message . includes ( "process aborted by user" )
@@ -136,8 +158,18 @@ export function useAgent() {
136158
137159 actions . setIsProcessing ( false )
138160 }
139- }
161+ } ,
162+ [ config , messageQueue , actions ]
163+ )
140164
141- runAgent ( )
142- } , [ ] )
165+ // Start listening for new messages from input
166+ useEffect ( ( ) => {
167+ const unsubscribe = messageQueue . subscribe ( ( userMessage ) => {
168+ setTimeout ( ( ) => {
169+ runQuery ( userMessage )
170+ } , 0 )
171+ } )
172+
173+ return unsubscribe
174+ } , [ messageQueue , runQuery ] )
143175}
0 commit comments