@@ -1039,6 +1039,123 @@ describe("Cline", () => {
10391039 await task . catch ( ( ) => { } )
10401040 } )
10411041 } )
1042+
1043+ describe ( "rate limiting" , ( ) => {
1044+ it ( "should use profile-specific rate limit when available" , async ( ) => {
1045+ const [ cline , task ] = Cline . create ( {
1046+ provider : mockProvider ,
1047+ apiConfiguration : mockApiConfig ,
1048+ task : "test task" ,
1049+ } )
1050+
1051+ // Set the lastApiRequestTime using Object.defineProperty to bypass private access
1052+ Object . defineProperty ( cline , "lastApiRequestTime" , {
1053+ value : Date . now ( ) - 2000 , // 2 seconds ago
1054+ writable : true ,
1055+ } )
1056+
1057+ // Mock the provider's getState to return profile-specific settings
1058+ mockProvider . getState = jest . fn ( ) . mockResolvedValue ( {
1059+ rateLimitSeconds : 5 , // Global rate limit of 5 seconds
1060+ currentApiConfigName : "test-profile" , // Current profile
1061+ profileSpecificSettings : {
1062+ "test-profile" : {
1063+ rateLimitSeconds : 10 , // Profile-specific rate limit of 10 seconds
1064+ } ,
1065+ } ,
1066+ } )
1067+
1068+ // Mock say to track rate limit delay messages
1069+ const saySpy = jest . spyOn ( cline , "say" )
1070+
1071+ // Create a successful stream for the API request with the correct type
1072+ const mockSuccessStream = ( async function * ( ) {
1073+ yield { type : "text" as const , text : "Success" }
1074+ } ) ( )
1075+
1076+ // Mock createMessage to return the success stream
1077+ jest . spyOn ( cline . api , "createMessage" ) . mockReturnValue ( mockSuccessStream as any )
1078+
1079+ // Mock delay to track countdown timing
1080+ const mockDelay = jest . fn ( ) . mockResolvedValue ( undefined )
1081+ jest . spyOn ( require ( "delay" ) , "default" ) . mockImplementation ( mockDelay )
1082+
1083+ // Trigger API request
1084+ const iterator = cline . attemptApiRequest ( 0 )
1085+ await iterator . next ( )
1086+
1087+ // Verify that the profile-specific rate limit was used (10 seconds)
1088+ // With 2 seconds elapsed, we should have an 8-second delay
1089+ expect ( saySpy ) . toHaveBeenCalledWith (
1090+ "api_req_retry_delayed" ,
1091+ expect . stringContaining ( "Rate limiting for 8 seconds" ) ,
1092+ undefined ,
1093+ true ,
1094+ )
1095+
1096+ // Clean up
1097+ await cline . abortTask ( true )
1098+ await task . catch ( ( ) => { } )
1099+ } )
1100+
1101+ it ( "should use global rate limit when no profile-specific setting exists" , async ( ) => {
1102+ const [ cline , task ] = Cline . create ( {
1103+ provider : mockProvider ,
1104+ apiConfiguration : mockApiConfig ,
1105+ task : "test task" ,
1106+ } )
1107+
1108+ // Set the lastApiRequestTime using Object.defineProperty to bypass private access
1109+ Object . defineProperty ( cline , "lastApiRequestTime" , {
1110+ value : Date . now ( ) - 2000 , // 2 seconds ago
1111+ writable : true ,
1112+ } )
1113+
1114+ // Mock the provider's getState to return only global settings
1115+ mockProvider . getState = jest . fn ( ) . mockResolvedValue ( {
1116+ rateLimitSeconds : 5 , // Global rate limit of 5 seconds
1117+ currentApiConfigName : "test-profile" , // Current profile
1118+ profileSpecificSettings : {
1119+ // No settings for test-profile
1120+ "other-profile" : {
1121+ rateLimitSeconds : 10 ,
1122+ } ,
1123+ } ,
1124+ } )
1125+
1126+ // Mock say to track rate limit delay messages
1127+ const saySpy = jest . spyOn ( cline , "say" )
1128+
1129+ // Create a successful stream for the API request with the correct type
1130+ const mockSuccessStream = ( async function * ( ) {
1131+ yield { type : "text" as const , text : "Success" }
1132+ } ) ( )
1133+
1134+ // Mock createMessage to return the success stream
1135+ jest . spyOn ( cline . api , "createMessage" ) . mockReturnValue ( mockSuccessStream as any )
1136+
1137+ // Mock delay to track countdown timing
1138+ const mockDelay = jest . fn ( ) . mockResolvedValue ( undefined )
1139+ jest . spyOn ( require ( "delay" ) , "default" ) . mockImplementation ( mockDelay )
1140+
1141+ // Trigger API request
1142+ const iterator = cline . attemptApiRequest ( 0 )
1143+ await iterator . next ( )
1144+
1145+ // Verify that the global rate limit was used (5 seconds)
1146+ // With 2 seconds elapsed, we should have a 3-second delay
1147+ expect ( saySpy ) . toHaveBeenCalledWith (
1148+ "api_req_retry_delayed" ,
1149+ expect . stringContaining ( "Rate limiting for 3 seconds" ) ,
1150+ undefined ,
1151+ true ,
1152+ )
1153+
1154+ // Clean up
1155+ await cline . abortTask ( true )
1156+ await task . catch ( ( ) => { } )
1157+ } )
1158+ } )
10421159 } )
10431160 } )
10441161} )
0 commit comments