@@ -8,43 +8,63 @@ import { ThunkApiType } from "../store";
88import { cancelStream } from "./cancelStream" ;
99import { saveCurrentSession } from "./session" ;
1010
11+ const OVERLOADED_RETRIES = 3 ;
12+ const OVERLOADED_DELAY_MS = 1000 ;
13+
14+ function isOverloadedErrorMessage ( message ?: string | null ) : boolean {
15+ if ( ! message ) return false ;
16+ const lower = message . toLowerCase ( ) ;
17+ return lower . includes ( "overloaded" ) || lower . includes ( "malformed json" ) ;
18+ }
19+
1120export const streamThunkWrapper = createAsyncThunk <
1221 void ,
1322 ( ) => Promise < void > ,
1423 ThunkApiType
15- > ( "chat/streamWrapper" , async ( runStream , { dispatch, extra, getState } ) => {
16- try {
17- await runStream ( ) ;
18- const state = getState ( ) ;
19- if ( ! state . session . isInEdit ) {
20- await dispatch (
21- saveCurrentSession ( {
22- openNewSession : false ,
23- generateTitle : true ,
24- } ) ,
25- ) ;
26- }
27- } catch ( e ) {
28- await dispatch ( cancelStream ( ) ) ;
29- dispatch ( setDialogMessage ( < StreamErrorDialog error = { e } /> ) ) ;
30- dispatch ( setShowDialog ( true ) ) ;
24+ > ( "chat/streamWrapper" , async ( runStream , { dispatch, getState } ) => {
25+ for ( let attempt = 0 ; attempt <= OVERLOADED_RETRIES ; attempt ++ ) {
26+ try {
27+ await runStream ( ) ;
28+ const state = getState ( ) ;
29+ if ( ! state . session . isInEdit ) {
30+ await dispatch (
31+ saveCurrentSession ( {
32+ openNewSession : false ,
33+ generateTitle : true ,
34+ } ) ,
35+ ) ;
36+ }
37+ return ;
38+ } catch ( e ) {
39+ // Get the selected model from the state for error analysis
40+ const state = getState ( ) ;
41+ const selectedModel = selectSelectedChatModel ( state ) ;
42+ const { parsedError, statusCode, message, modelTitle, providerName } =
43+ analyzeError ( e , selectedModel ) ;
3144
32- // Get the selected model from the state for error analysis
33- const state = getState ( ) ;
34- const selectedModel = selectSelectedChatModel ( state ) ;
45+ const shouldRetry =
46+ isOverloadedErrorMessage ( message ) && attempt < OVERLOADED_RETRIES ;
3547
36- const { parsedError, statusCode, modelTitle, providerName } = analyzeError (
37- e ,
38- selectedModel ,
39- ) ;
48+ if ( shouldRetry ) {
49+ await dispatch ( cancelStream ( ) ) ;
50+ const delayMs = OVERLOADED_DELAY_MS * 2 ** attempt ;
51+ await new Promise ( ( resolve ) => setTimeout ( resolve , delayMs ) ) ;
52+ await dispatch ( cancelStream ( ) ) ;
53+ } else {
54+ await dispatch ( cancelStream ( ) ) ;
55+ dispatch ( setDialogMessage ( < StreamErrorDialog error = { e } /> ) ) ;
56+ dispatch ( setShowDialog ( true ) ) ;
4057
41- const errorData = {
42- error_type : statusCode ? `HTTP ${ statusCode } ` : "Unknown" ,
43- error_message : parsedError ,
44- model_provider : providerName ,
45- model_title : modelTitle ,
46- } ;
58+ const errorData = {
59+ error_type : statusCode ? `HTTP ${ statusCode } ` : "Unknown" ,
60+ error_message : parsedError ,
61+ model_provider : providerName ,
62+ model_title : modelTitle ,
63+ } ;
4764
48- posthog . capture ( "gui_stream_error" , errorData ) ;
65+ posthog . capture ( "gui_stream_error" , errorData ) ;
66+ return ;
67+ }
68+ }
4969 }
5070} ) ;
0 commit comments