@@ -177,6 +177,26 @@ export class Indexer {
177177 this . saveFailedBatches ( existing ) ;
178178 }
179179
180+ private getProviderRateLimits ( provider : string ) : {
181+ concurrency : number ;
182+ intervalMs : number ;
183+ minRetryMs : number ;
184+ maxRetryMs : number ;
185+ } {
186+ switch ( provider ) {
187+ case "github-copilot" :
188+ return { concurrency : 1 , intervalMs : 4000 , minRetryMs : 5000 , maxRetryMs : 60000 } ;
189+ case "openai" :
190+ return { concurrency : 3 , intervalMs : 500 , minRetryMs : 1000 , maxRetryMs : 30000 } ;
191+ case "google" :
192+ return { concurrency : 5 , intervalMs : 200 , minRetryMs : 1000 , maxRetryMs : 30000 } ;
193+ case "ollama" :
194+ return { concurrency : 5 , intervalMs : 0 , minRetryMs : 500 , maxRetryMs : 5000 } ;
195+ default :
196+ return { concurrency : 3 , intervalMs : 1000 , minRetryMs : 1000 , maxRetryMs : 30000 } ;
197+ }
198+ }
199+
180200 async initialize ( ) : Promise < void > {
181201 this . detectedProvider = await detectEmbeddingProvider ( this . config . embeddingProvider ) ;
182202 if ( ! this . detectedProvider ) {
@@ -498,15 +518,17 @@ export class Indexer {
498518 }
499519 }
500520
501- // GitHub Models API rate limit: 15 requests/minute for embeddings
502- // Use concurrency 1 with 4-second delay to stay under limit (15 req/min = 1 req per 4 sec)
503- const queue = new PQueue ( { concurrency : 1 , interval : 4000 , intervalCap : 1 } ) ;
521+ const providerRateLimits = this . getProviderRateLimits ( detectedProvider . provider ) ;
522+ const queue = new PQueue ( {
523+ concurrency : providerRateLimits . concurrency ,
524+ interval : providerRateLimits . intervalMs ,
525+ intervalCap : providerRateLimits . concurrency
526+ } ) ;
504527 const dynamicBatches = createDynamicBatches ( chunksNeedingEmbedding ) ;
505528 let rateLimitBackoffMs = 0 ;
506529
507530 for ( const batch of dynamicBatches ) {
508531 queue . add ( async ( ) => {
509- // Additional backoff if we've been rate limited
510532 if ( rateLimitBackoffMs > 0 ) {
511533 await new Promise ( resolve => setTimeout ( resolve , rateLimitBackoffMs ) ) ;
512534 }
@@ -519,14 +541,13 @@ export class Indexer {
519541 } ,
520542 {
521543 retries : this . config . indexing . retries ,
522- minTimeout : Math . max ( this . config . indexing . retryDelayMs , 5000 ) , // Minimum 5s between retries
523- maxTimeout : 60000 , // Max 60s backoff
544+ minTimeout : Math . max ( this . config . indexing . retryDelayMs , providerRateLimits . minRetryMs ) ,
545+ maxTimeout : providerRateLimits . maxRetryMs ,
524546 factor : 2 ,
525547 onFailedAttempt : ( error ) => {
526548 const message = getErrorMessage ( error ) ;
527549 if ( isRateLimitError ( error ) ) {
528- // Exponential backoff: 10s, 20s, 40s...
529- rateLimitBackoffMs = Math . min ( 60000 , ( rateLimitBackoffMs || 5000 ) * 2 ) ;
550+ rateLimitBackoffMs = Math . min ( providerRateLimits . maxRetryMs , ( rateLimitBackoffMs || providerRateLimits . minRetryMs ) * 2 ) ;
530551 console . error (
531552 `Rate limited (attempt ${ error . attemptNumber } /${ error . retriesLeft + error . attemptNumber } ): waiting ${ rateLimitBackoffMs / 1000 } s before retry...`
532553 ) ;
@@ -539,7 +560,6 @@ export class Indexer {
539560 }
540561 ) ;
541562
542- // Success - gradually reduce backoff
543563 if ( rateLimitBackoffMs > 0 ) {
544564 rateLimitBackoffMs = Math . max ( 0 , rateLimitBackoffMs - 2000 ) ;
545565 }
0 commit comments