minimax-mcp-tools
Version:
Async MCP server with Minimax API integration for image generation and text-to-speech
104 lines • 3.33 kB
JavaScript
import { MinimaxRateLimitError } from '../utils/error-handler.js';
export class RateLimiter {
rpm;
burst;
window;
interval;
tokens;
lastRefill;
queue;
constructor({ rpm, burst = 1, window = 60000 }) {
this.rpm = rpm;
this.burst = burst;
this.window = window;
this.interval = window / rpm;
this.tokens = burst;
this.lastRefill = Date.now();
this.queue = [];
}
async acquire() {
return new Promise((resolve, reject) => {
this.queue.push({ resolve, reject, timestamp: Date.now() });
this.processQueue();
});
}
processQueue() {
if (this.queue.length === 0)
return;
this.refillTokens();
while (this.queue.length > 0 && this.tokens > 0) {
const request = this.queue.shift();
if (!request)
break;
this.tokens--;
const delay = Math.max(0, this.interval - (Date.now() - this.lastRefill));
setTimeout(() => this.processQueue(), delay);
request.resolve();
}
}
refillTokens() {
const now = Date.now();
const timePassed = now - this.lastRefill;
const tokensToAdd = Math.floor(timePassed / this.interval);
if (tokensToAdd > 0) {
this.tokens = Math.min(this.burst, this.tokens + tokensToAdd);
this.lastRefill = now;
}
}
getStatus() {
this.refillTokens();
return {
tokens: this.tokens,
queueLength: this.queue.length,
rpm: this.rpm,
burst: this.burst
};
}
reset() {
this.tokens = this.burst;
this.lastRefill = Date.now();
this.queue = [];
}
}
export class AdaptiveRateLimiter extends RateLimiter {
consecutiveErrors;
originalRpm;
backoffFactor;
recoveryFactor;
maxBackoff;
constructor(config) {
super(config);
this.consecutiveErrors = 0;
this.originalRpm = this.rpm;
this.backoffFactor = config.backoffFactor || 0.5;
this.recoveryFactor = config.recoveryFactor || 1.1;
this.maxBackoff = config.maxBackoff || 5;
}
onSuccess() {
if (this.consecutiveErrors > 0) {
this.consecutiveErrors = Math.max(0, this.consecutiveErrors - 1);
if (this.consecutiveErrors === 0) {
this.rpm = Math.min(this.originalRpm, this.rpm * this.recoveryFactor);
this.interval = this.window / this.rpm;
}
}
}
onError(error) {
if (error instanceof MinimaxRateLimitError) {
this.consecutiveErrors++;
const backoffMultiplier = Math.pow(this.backoffFactor, Math.min(this.consecutiveErrors, this.maxBackoff));
this.rpm = Math.max(1, this.originalRpm * backoffMultiplier);
this.interval = this.window / this.rpm;
this.tokens = Math.min(this.tokens, Math.floor(this.burst * backoffMultiplier));
}
}
getAdaptiveStatus() {
return {
...this.getStatus(),
consecutiveErrors: this.consecutiveErrors,
adaptedRpm: this.rpm,
originalRpm: this.originalRpm
};
}
}
//# sourceMappingURL=rate-limiter.js.map