Skip to content

Commit f80539f

Browse files
committed
Fix CLI retry loop on false stall
1 parent 2f1f15d commit f80539f

File tree

1 file changed

+5
-93
lines changed

1 file changed

+5
-93
lines changed

cli/src/hooks/use-send-message.ts

Lines changed: 5 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ const hiddenToolNames = new Set<ToolName | 'spawn_agent_inline'>([
3737
])
3838

3939
const STREAM_INACTIVITY_TIMEOUT_MS = 15_000
40-
const STREAM_STALL_TIMEOUT_MS = 4_000
4140
const MAX_RETRIES_PER_MESSAGE = 3
4241
const RETRY_BACKOFF_BASE_DELAY_MS = 1_000
4342
const RETRY_BACKOFF_MAX_DELAY_MS = 8_000
@@ -365,15 +364,7 @@ export const useSendMessage = ({
365364
null,
366365
)
367366
const streamInactivityTriggeredRef = useRef(false)
368-
const streamStallTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
369-
const streamStallTriggeredRef = useRef(false)
370367
const streamHadOutputRef = useRef(false)
371-
const autoRetryContextRef = useRef<{
372-
userMessageId: string
373-
content: string
374-
agentMode: AgentMode
375-
} | null>(null)
376-
const sendMessageSelfRef = useRef<SendMessageFn | null>(null)
377368
const currentRunContextRef = useRef<{
378369
userMessageId: string
379370
content: string
@@ -613,16 +604,8 @@ export const useSendMessage = ({
613604
}
614605
}, [])
615606

616-
const clearStreamStallTimer = useCallback(() => {
617-
if (streamStallTimerRef.current) {
618-
clearTimeout(streamStallTimerRef.current)
619-
streamStallTimerRef.current = null
620-
}
621-
}, [])
622-
623607
const handleStreamInactivityTimeout = useCallback(() => {
624608
clearStreamInactivityTimer()
625-
clearStreamStallTimer()
626609
const context = currentRunContextRef.current
627610
if (!context) {
628611
return
@@ -636,12 +619,7 @@ export const useSendMessage = ({
636619
if (controller && !controller.signal.aborted) {
637620
controller.abort(new Error('Stream inactivity timeout'))
638621
}
639-
}, [
640-
abortControllerRef,
641-
clearStreamStallTimer,
642-
clearStreamInactivityTimer,
643-
schedulePendingRetry,
644-
])
622+
}, [abortControllerRef, clearStreamInactivityTimer, schedulePendingRetry])
645623

646624
const refreshStreamInactivityTimer = useCallback(() => {
647625
clearStreamInactivityTimer()
@@ -654,50 +632,17 @@ export const useSendMessage = ({
654632
)
655633
}, [clearStreamInactivityTimer, handleStreamInactivityTimeout])
656634

657-
const handleStreamStallTimeout = useCallback(() => {
658-
if (!currentRunContextRef.current || !streamHadOutputRef.current) {
659-
return
660-
}
661-
clearStreamStallTimer()
662-
streamStallTriggeredRef.current = true
663-
autoRetryContextRef.current = {
664-
userMessageId: currentRunContextRef.current.userMessageId,
665-
content: currentRunContextRef.current.content,
666-
agentMode: currentRunContextRef.current.agentMode,
667-
}
668-
schedulePendingRetry({
669-
...currentRunContextRef.current,
670-
note: 'Stream stalled…',
671-
})
672-
const controller = abortControllerRef.current
673-
if (controller && !controller.signal.aborted) {
674-
controller.abort(new Error('Stream stalled'))
675-
}
676-
}, [abortControllerRef, clearStreamStallTimer, schedulePendingRetry])
677-
678-
const refreshStreamStallTimer = useCallback(() => {
679-
if (!currentRunContextRef.current || !streamHadOutputRef.current) {
680-
return
681-
}
682-
clearStreamStallTimer()
683-
streamStallTimerRef.current = setTimeout(
684-
handleStreamStallTimeout,
685-
STREAM_STALL_TIMEOUT_MS,
686-
)
687-
}, [clearStreamStallTimer, handleStreamStallTimeout])
688-
689635
useEffect(() => {
690636
return () => {
691637
if (flushTimeoutRef.current) {
692638
clearTimeout(flushTimeoutRef.current)
693639
flushTimeoutRef.current = null
694640
}
695641
clearStreamInactivityTimer()
696-
clearStreamStallTimer()
697642
currentRunContextRef.current = null
698643
flushPendingUpdates()
699644
}
700-
}, [clearStreamInactivityTimer, clearStreamStallTimer, flushPendingUpdates])
645+
}, [clearStreamInactivityTimer, flushPendingUpdates])
701646

702647
const sendMessage = useCallback<SendMessageFn>(
703648
async (params: ParamsOf<SendMessageFn>) => {
@@ -1176,17 +1121,13 @@ export const useSendMessage = ({
11761121
let actualCredits: number | undefined = undefined
11771122

11781123
streamHadOutputRef.current = false
1179-
streamStallTriggeredRef.current = false
1180-
clearStreamStallTimer()
11811124

11821125
const abortController = new AbortController()
11831126
abortControllerRef.current = abortController
11841127
abortController.signal.addEventListener('abort', () => {
11851128
clearStreamInactivityTimer()
1186-
clearStreamStallTimer()
11871129
currentRunContextRef.current = null
11881130
streamHadOutputRef.current = false
1189-
streamStallTriggeredRef.current = false
11901131
setStreamStatus('idle')
11911132
setCanProcessQueue(false)
11921133
updateChainInProgress(false)
@@ -1234,7 +1175,6 @@ export const useSendMessage = ({
12341175
if (!streamHadOutputRef.current) {
12351176
streamHadOutputRef.current = true
12361177
}
1237-
refreshStreamStallTimer()
12381178
if (
12391179
typeof event === 'string' ||
12401180
(event.type === 'reasoning_chunk' &&
@@ -2007,10 +1947,8 @@ export const useSendMessage = ({
20071947

20081948
if (!runState.output || runState.output.type === 'error') {
20091949
clearStreamInactivityTimer()
2010-
clearStreamStallTimer()
20111950
currentRunContextRef.current = null
20121951
streamHadOutputRef.current = false
2013-
streamStallTriggeredRef.current = false
20141952
setCanProcessQueue(false)
20151953

20161954
const errorMessage =
@@ -2044,10 +1982,8 @@ export const useSendMessage = ({
20441982
}
20451983

20461984
clearStreamInactivityTimer()
2047-
clearStreamStallTimer()
20481985
currentRunContextRef.current = null
20491986
streamHadOutputRef.current = false
2050-
streamStallTriggeredRef.current = false
20511987
setStreamStatus('idle')
20521988
if (resumeQueue && !isQueuePausedRef?.current) {
20531989
resumeQueue()
@@ -2091,10 +2027,8 @@ export const useSendMessage = ({
20912027
'SDK client.run() failed',
20922028
)
20932029
clearStreamInactivityTimer()
2094-
clearStreamStallTimer()
20952030
currentRunContextRef.current = null
20962031
streamHadOutputRef.current = false
2097-
streamStallTriggeredRef.current = false
20982032
setStreamStatus('idle')
20992033
setCanProcessQueue(false)
21002034
updateChainInProgress(false)
@@ -2133,12 +2067,9 @@ export const useSendMessage = ({
21332067
userMessageId in pendingRetriesRef.current
21342068
const timedOutDueToSdk =
21352069
isNetworkError(error) && Boolean(error.streamTimedOut)
2136-
const streamStalled = streamStallTriggeredRef.current
21372070
streamInactivityTriggeredRef.current = false
2138-
streamStallTriggeredRef.current = false
21392071

21402072
const shouldRetryError =
2141-
streamStalled ||
21422073
timedOutDueToCli ||
21432074
timedOutDueToSdk ||
21442075
!isConnectedRef.current ||
@@ -2154,18 +2085,15 @@ export const useSendMessage = ({
21542085
if (resumeQueue && !isQueuePausedRef?.current) {
21552086
resumeQueue()
21562087
}
2157-
autoRetryContextRef.current = null
21582088
return
21592089
}
21602090

21612091
if (!pendingAlreadyScheduled) {
21622092
const note = !isConnectedRef.current
21632093
? 'Waiting for connection…'
2164-
: streamStalled
2165-
? 'Stream stalled…'
2166-
: timedOutDueToCli || timedOutDueToSdk
2167-
? 'Timed out…'
2168-
: 'Stream interrupted'
2094+
: timedOutDueToCli || timedOutDueToSdk
2095+
? 'Timed out…'
2096+
: 'Stream interrupted'
21692097

21702098
schedulePendingRetry({
21712099
userMessageId,
@@ -2175,20 +2103,6 @@ export const useSendMessage = ({
21752103
})
21762104
}
21772105
}
2178-
const autoRetryContext = autoRetryContextRef.current
2179-
if (
2180-
autoRetryContext &&
2181-
autoRetryContext.userMessageId === userMessageId
2182-
) {
2183-
autoRetryContextRef.current = null
2184-
setTimeout(() => {
2185-
sendMessageSelfRef.current?.({
2186-
content: autoRetryContext.content,
2187-
agentMode: autoRetryContext.agentMode,
2188-
retryOfMessageId: autoRetryContext.userMessageId,
2189-
})
2190-
}, 0)
2191-
}
21922106
},
21932107
[
21942108
applyMessageUpdate,
@@ -2224,7 +2138,6 @@ export const useSendMessage = ({
22242138
isConnectedRef,
22252139
markAiMessageInterrupted,
22262140
markUserMessageFailed,
2227-
sendMessageSelfRef,
22282141
],
22292142
)
22302143

@@ -2340,7 +2253,6 @@ export const useSendMessage = ({
23402253
setCanProcessQueue,
23412254
])
23422255

2343-
sendMessageSelfRef.current = sendMessage
23442256

23452257
return {
23462258
sendMessage,

0 commit comments

Comments
 (0)