Files
antigravity-claude-proxy/src/account-manager/strategies/index.js
Badri Narayanan S 5ae19a5b72 feat: add configurable account selection strategies
Refactor account selection into a strategy pattern with three options:
- Sticky: cache-optimized, stays on same account until rate-limited
- Round-robin: load-balanced, rotates every request
- Hybrid (default): smart distribution using health scores, token buckets, and LRU

The hybrid strategy uses multiple signals for optimal account selection:
health tracking for reliability, client-side token buckets for rate limiting,
and LRU freshness to prefer rested accounts.

Includes WebUI settings for strategy selection and unit tests.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-18 03:48:43 +05:30

86 lines
2.8 KiB
JavaScript

/**
* Strategy Factory
*
* Creates and exports account selection strategy instances.
*/
import { StickyStrategy } from './sticky-strategy.js';
import { RoundRobinStrategy } from './round-robin-strategy.js';
import { HybridStrategy } from './hybrid-strategy.js';
import { logger } from '../../utils/logger.js';
import {
SELECTION_STRATEGIES,
DEFAULT_SELECTION_STRATEGY
} from '../../constants.js';
// Re-export strategy constants for convenience
export const STRATEGY_NAMES = SELECTION_STRATEGIES;
export const DEFAULT_STRATEGY = DEFAULT_SELECTION_STRATEGY;
// Strategy display labels
export const STRATEGY_LABELS = {
'sticky': 'Sticky (Cache Optimized)',
'round-robin': 'Round Robin (Load Balanced)',
'hybrid': 'Hybrid (Smart Distribution)'
};
/**
* Create a strategy instance
* @param {string} strategyName - Name of the strategy ('sticky', 'round-robin', 'hybrid')
* @param {Object} config - Strategy configuration
* @returns {BaseStrategy} The strategy instance
*/
export function createStrategy(strategyName, config = {}) {
const name = (strategyName || DEFAULT_STRATEGY).toLowerCase();
switch (name) {
case 'sticky':
logger.debug('[Strategy] Creating StickyStrategy');
return new StickyStrategy(config);
case 'round-robin':
case 'roundrobin':
logger.debug('[Strategy] Creating RoundRobinStrategy');
return new RoundRobinStrategy(config);
case 'hybrid':
logger.debug('[Strategy] Creating HybridStrategy');
return new HybridStrategy(config);
default:
logger.warn(`[Strategy] Unknown strategy "${strategyName}", falling back to ${DEFAULT_STRATEGY}`);
return new HybridStrategy(config);
}
}
/**
* Check if a strategy name is valid
* @param {string} name - Strategy name to check
* @returns {boolean} True if valid
*/
export function isValidStrategy(name) {
if (!name) return false;
const lower = name.toLowerCase();
return STRATEGY_NAMES.includes(lower) || lower === 'roundrobin';
}
/**
* Get the display label for a strategy
* @param {string} name - Strategy name
* @returns {string} Display label
*/
export function getStrategyLabel(name) {
const lower = (name || DEFAULT_STRATEGY).toLowerCase();
if (lower === 'roundrobin') return STRATEGY_LABELS['round-robin'];
return STRATEGY_LABELS[lower] || STRATEGY_LABELS[DEFAULT_STRATEGY];
}
// Re-export strategies for direct use
export { StickyStrategy } from './sticky-strategy.js';
export { RoundRobinStrategy } from './round-robin-strategy.js';
export { HybridStrategy } from './hybrid-strategy.js';
export { BaseStrategy } from './base-strategy.js';
// Re-export trackers
export { HealthTracker, TokenBucketTracker } from './trackers/index.js';