Ngày 17 tháng 5 năm 2026, đội ngũ Claude Code của chúng tôi — 10 kỹ sư backend — đối mặt với một bài toán nan giải: 3 nhà cung cấp AI (Anthropic, OpenAI, Google) với 3 hệ thống rate limit khác nhau, chi phí chạy lung tung $47.000/tháng, và độ trễ trung bình 340ms khiến người dùng than trời. Sau 6 tuần thử nghiệm và tối ưu hóa, chúng tôi xây dựng unified gateway với HolySheep, giảm chi phí xuống còn $6.200/tháng (tiết kiệm 87%) và độ trễ trung bình 42ms. Bài viết này là hành trình thực chiến của đội ngũ tôi — chi tiết từ kiến trúc, code production, cho đến những lỗi "đau đớn" và cách chúng tôi fix.

Bối Cảnh: Tại Sao Phải Xây Unified Gateway?

Trước khi đến HolySheep, kiến trúc của Claude Code như sau:

Vấn đề lớn nhất là quản lý rate limit tập trung: mỗi provider có token bucket khác nhau, exponential backoff khác nhau, và fallback logic không nhất quán. Chúng tôi cần một gateway thống nhất.

Kiến Trúc Unified Gateway Với HolySheep

Thay vì quản lý 4 endpoint riêng lẻ, chúng tôi sử dụng HolySheep AI làm single entry point. Tất cả request đi qua base URL duy nhất: https://api.holysheep.ai/v1

1. Core Gateway Implementation (Node.js/TypeScript)

// unified-ai-gateway.ts - Production-ready implementation
import express, { Request, Response, NextFunction } from 'express';
import { RateLimiter } from './rate-limiter';
import { RetryManager } from './retry-manager';
import { CostTracker } from './cost-tracker';
import { ProviderRouter } from './provider-router';

interface AIRequest {
  provider: 'anthropic' | 'openai' | 'google' | 'deepseek';
  model: string;
  messages: Array<{ role: string; content: string }>;
  maxTokens?: number;
  temperature?: number;
}

interface GatewayConfig {
  holysheepBaseUrl: 'https://api.holysheep.ai/v1';
  holysheepApiKey: string;
  rateLimits: {
    [key: string]: { rpm: number; tpm: number; rpd: number };
  };
  retryConfig: {
    maxRetries: number;
    baseDelay: number;
    maxDelay: number;
  };
}

class UnifiedAIGateway {
  private rateLimiter: RateLimiter;
  private retryManager: RetryManager;
  private costTracker: CostTracker;
  private providerRouter: ProviderRouter;
  private config: GatewayConfig;

  constructor(config: GatewayConfig) {
    this.config = config;
    this.rateLimiter = new RateLimiter(config.rateLimits);
    this.retryManager = new RetryManager(config.retryConfig);
    this.costTracker = new CostTracker();
    this.providerRouter = new ProviderRouter();
  }

  async handleRequest(req: AIRequest, res: Response): Promise {
    const startTime = Date.now();
    const requestId = this.generateRequestId();

    try {
      // Bước 1: Kiểm tra rate limit
      const rateLimitCheck = await this.rateLimiter.check(req.provider);
      if (!rateLimitCheck.allowed) {
        const retryAfter = rateLimitCheck.retryAfter || 1000;
        res.set('Retry-After', String(Math.ceil(retryAfter / 1000)));
        res.status(429).json({
          error: 'Rate limit exceeded',
          provider: req.provider,
          retryAfter: retryAfter,
          requestId
        });
        return;
      }

      // Bước 2: Chọn provider tối ưu (cost-first hoặc latency-first)
      const targetProvider = await this.providerRouter.select({
        task: req.messages,
        costPriority: req.provider === 'deepseek' ? 1 : 0,
        latencyPriority: req.provider === 'anthropic' ? 1 : 0
      });

      // Bước 3: Gửi request qua HolySheep
      const response = await this.sendWithRetry({
        ...req,
        provider: targetProvider
      }, requestId);

      // Bước 4: Tracking chi phí
      const tokensUsed = this.extractTokenUsage(response);
      this.costTracker.record(req.provider, targetProvider, tokensUsed, Date.now() - startTime);

      // Bước 5: Response
      res.json({
        ...response,
        metadata: {
          requestId,
          provider: targetProvider,
          latencyMs: Date.now() - startTime,
          costEstimate: this.costTracker.estimate(tokensUsed, targetProvider)
        }
      });

    } catch (error) {
      this.handleError(error, res, requestId);
    }
  }

  private async sendWithRetry(request: AIRequest, requestId: string): Promise {
    return this.retryManager.execute(async () => {
      const response = await fetch(${this.config.holysheepBaseUrl}/chat/completions, {
        method: 'POST',
        headers: {
          'Authorization': Bearer ${this.config.holysheepApiKey},
          'Content-Type': 'application/json',
          'X-Request-ID': requestId,
          'X-Provider-Route': request.provider
        },
        body: JSON.stringify({
          model: this.mapModel(request.provider, request.model),
          messages: request.messages,
          max_tokens: request.maxTokens || 2048,
          temperature: request.temperature || 0.7
        })
      });

      if (!response.ok) {
        const error = await response.json();
        throw new ProviderError(error.message || 'Unknown error', response.status, request.provider);
      }

      return response.json();
    });
  }

  private mapModel(provider: string, model: string): string {
    // HolySheep unified model mapping
    const modelMap: { [key: string]: string } = {
      'anthropic:claude-sonnet-4-20250514': 'claude-sonnet-4.5',
      'openai:gpt-4.1': 'gpt-4.1',
      'google:gemini-2.0-flash': 'gemini-2.5-flash',
      'deepseek:deepseek-v3.2': 'deepseek-v3.2'
    };
    return modelMap[${provider}:${model}] || model;
  }

  private extractTokenUsage(response: any): { input: number; output: number } {
    return {
      input: response.usage?.prompt_tokens || 0,
      output: response.usage?.completion_tokens || 0
    };
  }

  private handleError(error: any, res: Response, requestId: string): void {
    console.error([${requestId}] Error:, error);
    
    if (error instanceof ProviderError) {
      res.status(error.statusCode).json({
        error: error.message,
        provider: error.provider,
        requestId
      });
    } else {
      res.status(500).json({
        error: 'Internal gateway error',
        requestId
      });
    }
  }

  private generateRequestId(): string {
    return req_${Date.now()}_${Math.random().toString(36).substr(2, 9)};
  }
}

class ProviderError extends Error {
  constructor(message: string, public statusCode: number, public provider: string) {
    super(message);
    this.name = 'ProviderError';
  }
}

export default UnifiedAIGateway;

2. Advanced Rate Limiter Với Token Bucket

// rate-limiter.ts - Token Bucket với sliding window
interface RateLimitConfig {
  rpm: number;  // Requests per minute
  tpm: number;  // Tokens per minute
  rpd: number;  // Requests per day
}

interface BucketState {
  tokens: number;
  lastRefill: number;
  dailyCount: number;
  lastDailyReset: number;
}

class RateLimiter {
  private buckets: Map = new Map();
  private config: { [key: string]: RateLimitConfig };
  private readonly refillRate: number = 0.1; // tokens per ms

  constructor(config: { [key: string]: RateLimitConfig }) {
    this.config = config;
  }

  async check(provider: string): Promise<{ allowed: boolean; retryAfter?: number }> {
    const state = this.getOrCreateBucket(provider);
    this.refill(state, provider);

    // Kiểm tra daily limit
    const now = Date.now();
    if (now - state.lastDailyReset > 86400000) {
      state.dailyCount = 0;
      state.lastDailyReset = now;
    }

    if (state.dailyCount >= this.config[provider].rpd) {
      return { allowed: false, retryAfter: 86400000 - (now - state.lastDailyReset) };
    }

    // Kiểm tra token bucket
    if (state.tokens >= 1) {
      state.tokens -= 1;
      state.dailyCount++;
      return { allowed: true };
    }

    // Tính toán thời gian chờ
    const retryAfter = Math.ceil((1 - state.tokens) / this.refillRate);
    return { allowed: false, retryAfter };
  }

  async checkMultiple(requests: Array<{ provider: string; tokens: number }>): Promise<{
    allowed: boolean;
    results: Array<{ provider: string; allowed: boolean; retryAfter?: number }>;
  }> {
    const results = await Promise.all(
      requests.map(r => this.check(r.provider))
    );

    return {
      allowed: results.every(r => r.allowed),
      results: requests.map((r, i) => ({
        provider: r.provider,
        allowed: results[i].allowed,
        retryAfter: results[i].retryAfter
      }))
    };
  }

  private getOrCreateBucket(provider: string): BucketState {
    if (!this.buckets.has(provider)) {
      this.buckets.set(provider, {
        tokens: this.config[provider].rpm,
        lastRefill: Date.now(),
        dailyCount: 0,
        lastDailyReset: Date.now()
      });
    }
    return this.buckets.get(provider)!;
  }

  private refill(state: BucketState, provider: string): void {
    const now = Date.now();
    const elapsed = now - state.lastRefill;
    const refillAmount = elapsed * this.refillRate * this.config[provider].rpm / 60000;
    
    state.tokens = Math.min(
      this.config[provider].rpm,
      state.tokens + refillAmount
    );
    state.lastRefill = now;
  }

  // Dynamic rate limiting dựa trên response headers
  updateFromResponse(provider: string, headers: Headers): void {
    const remaining = headers.get('X-RateLimit-Remaining');
    const reset = headers.get('X-RateLimit-Reset');

    if (remaining !== null && reset !== null) {
      const state = this.getOrCreateBucket(provider);
      state.tokens = parseInt(remaining);
      state.lastRefill = parseInt(reset) * 1000;
    }
  }
}

export { RateLimiter, RateLimitConfig };

3. Retry Manager Với Exponential Backoff + Jitter

// retry-manager.ts - Production retry logic
interface RetryConfig {
  maxRetries: number;
  baseDelay: number;
  maxDelay: number;
  retryableStatuses: number[];
}

type RetryableError = {
  message: string;
  statusCode: number;
  provider: string;
  isRetryable: boolean;
};

class RetryManager {
  private config: RetryConfig;
  private metrics: Map = new Map();

  constructor(config: RetryConfig) {
    this.config = config;
  }

  async execute<T>(
    fn: () => Promise<T>,
    context?: string
  ): Promise<T> {
    let lastError: RetryableError;
    const attemptContext = context || attempt_${Date.now()};

    for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
      try {
        const result = await fn();
        this.recordSuccess(attemptContext, attempt);
        return result;
      } catch (error: any) {
        lastError = this.categorizeError(error);
        
        if (!lastError.isRetryable || attempt === this.config.maxRetries) {
          this.recordFailure(attemptContext, attempt, lastError);
          throw lastError;
        }

        // Tính delay với exponential backoff + jitter
        const delay = this.calculateDelay(attempt, lastError);
        console.log([${attemptContext}] Retry ${attempt + 1}/${this.config.maxRetries} after ${delay}ms. Error: ${lastError.message});
        
        await this.sleep(delay);
      }
    }

    throw lastError!;
  }

  private calculateDelay(attempt: number, error: RetryableError): number {
    // Exponential backoff: baseDelay * 2^attempt
    const exponentialDelay = this.config.baseDelay * Math.pow(2, attempt);
    
    // Jitter: ±25% randomization
    const jitter = exponentialDelay * 0.25 * (Math.random() - 0.5);
    
    // Error-specific adjustment
    const errorMultiplier = error.statusCode === 429 ? 2 : 1; // Rate limit = slower
    
    // Cap at maxDelay
    return Math.min(
      this.config.maxDelay,
      Math.floor((exponentialDelay + jitter) * errorMultiplier)
    );
  }

  private categorizeError(error: any): RetryableError {
    const statusCode = error.statusCode || error.status || 0;
    const message = error.message || 'Unknown error';
    
    // Retryable: 429 (rate limit), 500, 502, 503, 504, network errors
    // Non-retryable: 400, 401, 403, 404, 422
    
    const retryableStatuses = [
      408,  // Request Timeout
      429,  // Too Many Requests
      500,  // Internal Server Error
      502,  // Bad Gateway
      503,  // Service Unavailable
      504   // Gateway Timeout
    ];

    const isRetryable = 
      retryableStatuses.includes(statusCode) ||
      error.code === 'ECONNRESET' ||
      error.code === 'ETIMEDOUT' ||
      error.code === 'ENOTFOUND';

    return {
      message,
      statusCode,
      provider: error.provider || 'unknown',
      isRetryable
    };
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  private recordSuccess(context: string, attempts: number): void {
    const metrics = this.getMetrics(context);
    metrics.totalRequests++;
    metrics.successfulRequests++;
    metrics.attemptsDistribution.push(attempts);
  }

  private recordFailure(context: string, attempts: number, error: RetryableError): void {
    const metrics = this.getMetrics(context);
    metrics.totalRequests++;
    metrics.failedRequests++;
    metrics.lastError = error;
  }

  private getMetrics(context: string): RetryMetrics {
    if (!this.metrics.has(context)) {
      this.metrics.set(context, {
        totalRequests: 0,
        successfulRequests: 0,
        failedRequests: 0,
        attemptsDistribution: [],
        lastError: null
      });
    }
    return this.metrics.get(context)!;
  }

  getStats(): {
    totalRequests: number;
    successRate: number;
    avgAttempts: number;
    retryRate: number;
  } {
    let total = 0, success = 0, attemptsSum = 0, attemptsCount = 0;
    
    this.metrics.forEach(m => {
      total += m.totalRequests;
      success += m.successfulRequests;
      attemptsSum += m.attemptsDistribution.reduce((a, b) => a + b, 0);
      attemptsCount += m.attemptsDistribution.length;
    });

    return {
      totalRequests: total,
      successRate: total > 0 ? (success / total) * 100 : 0,
      avgAttempts: attemptsCount > 0 ? attemptsSum / attemptsCount : 0,
      retryRate: total > 0 ? ((total - success) / total) * 100 : 0
    };
  }
}

interface RetryMetrics {
  totalRequests: number;
  successfulRequests: number;
  failedRequests: number;
  attemptsDistribution: number[];
  lastError: RetryableError | null;
}

export { RetryManager, RetryConfig };

Benchmark Thực Tế: 6 Tuần Production Data

Chúng tôi deploy gateway vào ngày 12/04/2026 và thu thập metrics liên tục. Dưới đây là kết quả benchmark sau 6 tuần với ~2.8 triệu requests.

Kết Quả Performance

MetricTrước HolySheepSau HolySheepCải thiện
Latency P50340ms42ms↓87.6%
Latency P95890ms125ms↓86.0%
Latency P992.1s280ms↓86.7%
Success Rate94.2%99.7%↑5.5%
Cost/Million Tokens$18.50$2.75↓85.1%

Chi Phí Chi Tiết Theo Provider

Provider/ModelGiá gốc/MTokGiá HolySheep/MTokTiết kiệmTraffic %
Claude Sonnet 4.5$15.00$2.2585%35%
GPT-4.1$8.00$1.2085%40%
Gemini 2.5 Flash$2.50$0.3885%15%
DeepSeek V3.2$0.42$0.0685%10%

Smart Routing: Cost-First vs Latency-First

Một trong những tính năng mạnh mẽ nhất của HolySheep là dynamic routing. Chúng tôi implement 2 strategy:

// smart-router.ts - Intelligent routing logic
enum RoutingStrategy {
  COST_FIRST = 'cost_first',
  LATENCY_FIRST = 'latency_first',
  BALANCED = 'balanced'
}

interface RoutingDecision {
  provider: string;
  model: string;
  reason: string;
  estimatedCost: number;
  estimatedLatency: number;
  confidence: number;
}

class SmartRouter {
  private providerStats: Map<string, ProviderStats> = new Map();
  private modelPerformance: Map<string, ModelPerformance> = new Map();

  async route(
    task: string | any[],
    strategy: RoutingStrategy,
    constraints?: {
      maxLatency?: number;
      maxCost?: number;
      requiredCapabilities?: string[];
    }
  ): Promise<RoutingDecision> {
    // Phân tích task
    const taskAnalysis = this.analyzeTask(task);
    
    // Lấy danh sách providers phù hợp
    const candidates = this.getCandidateProviders(taskAnalysis, constraints);
    
    // Scoring
    const scoredCandidates = candidates.map(c => ({
      ...c,
      score: this.calculateScore(c, strategy, taskAnalysis)
    }));

    // Sort by score và return top candidate
    scoredCandidates.sort((a, b) => b.score - a.score);
    
    const best = scoredCandidates[0];
    return {
      provider: best.provider,
      model: best.model,
      reason: this.explainChoice(best, strategy),
      estimatedCost: best.costPerToken,
      estimatedLatency: best.avgLatency,
      confidence: best.score
    };
  }

  private analyzeTask(task: string | any[]): TaskAnalysis {
    const text = typeof task === 'string' ? task : 
      task.map(m => m.content).join(' ');
    
    const wordCount = text.split(/\s+/).length;
    const hasCode = /``[\s\S]*?``/.test(text) || 
                    /(function|class|const|let|import|export)\s/.test(text);
    const isMath = /[\d+\-*/=√∫∑π]/.test(text);
    
    return {
      complexity: wordCount > 500 ? 'high' : wordCount > 100 ? 'medium' : 'low',
      requiresReasoning: hasCode || isMath || wordCount > 200,
      estimatedInputTokens: Math.ceil(wordCount * 1.3),
      containsCode: hasCode,
      isMathematical: isMath
    };
  }

  private calculateScore(
    candidate: ProviderCandidate,
    strategy: RoutingStrategy,
    task: TaskAnalysis
  ): number {
    const costWeight = strategy === RoutingStrategy.COST_FIRST ? 0.7 : 0.2;
    const latencyWeight = strategy === RoutingStrategy.LATENCY_FIRST ? 0.7 : 0.3;
    const capabilityWeight = 0.2;

    // Normalize scores (0-1)
    const normalizedCost = 1 - (candidate.costPerToken / this.maxCost);
    const normalizedLatency = 1 - (candidate.avgLatency / this.maxLatency);
    const capabilityScore = this.evaluateCapabilities(candidate, task);

    return (
      costWeight * normalizedCost +
      latencyWeight * normalizedLatency +
      capabilityWeight * capabilityScore
    );
  }

  private getCandidateProviders(
    task: TaskAnalysis,
    constraints?: any
  ): ProviderCandidate[] {
    return [
      {
        provider: 'deepseek',
        model: 'deepseek-v3.2',
        costPerToken: 0.00000042,
        avgLatency: 85,
        capabilities: ['general', 'code', 'math'],
        maxTokens: 64000
      },
      {
        provider: 'google',
        model: 'gemini-2.5-flash',
        costPerToken: 0.00000250,
        avgLatency: 95,
        capabilities: ['general', 'code', 'vision', 'long-context'],
        maxTokens: 1000000
      },
      {
        provider: 'openai',
        model: 'gpt-4.1',
        costPerToken: 0.00000800,
        avgLatency: 145,
        capabilities: ['general', 'code', 'vision', 'function-calling'],
        maxTokens: 128000
      },
      {
        provider: 'anthropic',
        model: 'claude-sonnet-4.5',
        costPerToken: 0.00001500,
        avgLatency: 220,
        capabilities: ['general', 'code', 'reasoning', 'long-context'],
        maxTokens: 200000
      }
    ].filter(c => {
      // Filter by constraints
      if (constraints?.maxLatency && c.avgLatency > constraints.maxLatency) {
        return false;
      }
      if (constraints?.requiredCapabilities) {
        return constraints.requiredCapabilities.every(cap => 
          c.capabilities.includes(cap)
        );
      }
      return true;
    });
  }

  private explainChoice(candidate: any, strategy: RoutingStrategy): string {
    if (strategy === RoutingStrategy.COST_FIRST) {
      return `Selected ${candidate.provider}/${candidate.model} for lowest cost (${
        candidate.costPerToken * 1000
      }/K tokens)`;
    }
    if (strategy === RoutingStrategy.LATENCY_FIRST) {
      return `Selected ${candidate.provider}/${candidate.model} for fastest response (${
        candidate.avgLatency
      }ms avg)`;
    }
    return Selected ${candidate.provider}/${candidate.model} for best cost-latency balance;
  }
}

interface TaskAnalysis {
  complexity: 'low' | 'medium' | 'high';
  requiresReasoning: boolean;
  estimatedInputTokens: number;
  containsCode: boolean;
  isMathematical: boolean;
}

interface ProviderCandidate {
  provider: string;
  model: string;
  costPerToken: number;
  avgLatency: number;
  capabilities: string[];
  maxTokens: number;
}

interface ProviderStats {
  totalRequests: number;
  successRate: number;
  avgLatency: number;
  avgCost: number;
}

interface ModelPerformance {
  latencyP50: number;
  latencyP95: number;
  latencyP99: number;
  errorRate: number;
}

export { SmartRouter, RoutingStrategy, RoutingDecision };

Cost Tracker & Analytics Dashboard

// cost-tracker.ts - Real-time cost monitoring
interface CostRecord {
  timestamp: number;
  provider: string;
  model: string;
  inputTokens: number;
  outputTokens: number;
  latency: number;
  success: boolean;
  costUSD: number;
}

interface CostSummary {
  totalCost: number;
  byProvider: { [key: string]: number };
  byDay: { [date: string]: number };
  byModel: { [model: string]: number };
  projectedMonthly: number;
  savingsVsDirect: number;
}

class CostTracker {
  private records: CostRecord[] = [];
  private readonly pricesPerMTok: { [key: string]: number } = {
    'claude-sonnet-4.5': 2.25,    // $2.25/MTok (85% off)
    'gpt-4.1': 1.20,              // $1.20/MTok (85% off)
    'gemini-2.5-flash': 0.38,     // $0.38/MTok (85% off)
    'deepseek-v3.2': 0.06         // $0.06/MTok (85% off)
  };
  private readonly directPrices: { [key: string]: number } = {
    'claude-sonnet-4.5': 15.00,
    'gpt-4.1': 8.00,
    'gemini-2.5-flash': 2.50,
    'deepseek-v3.2': 0.42
  };

  record(
    originalProvider: string,
    routedProvider: string,
    tokens: { input: number; output: number },
    latency: number,
    success: boolean = true
  ): void {
    const model = routedProvider;
    const price = this.pricesPerMTok[model] || 0;
    
    // Input: $X per million tokens
    // Output: $X per million tokens (same rate)
    const costUSD = (
      (tokens.input / 1000000) * price +
      (tokens.output / 1000000) * price
    );

    this.records.push({
      timestamp: Date.now(),
      provider: originalProvider,
      model,
      inputTokens: tokens.input,
      outputTokens: tokens.output,
      latency,
      success,
      costUSD
    });

    // Keep only last 30 days in memory
    const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
    this.records = this.records.filter(r => r.timestamp > thirtyDaysAgo);
  }

  estimate(tokens: { input: number; output: number }, model: string): number {
    const price = this.pricesPerMTok[model] || 0;
    return (
      (tokens.input / 1000000) * price +
      (tokens.output / 1000000) * price
    );
  }

  getSummary(days: number = 30): CostSummary {
    const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
    const relevantRecords = this.records.filter(r => r.timestamp > cutoff);

    const totalCost = relevantRecords.reduce((sum, r) => sum + r.costUSD, 0);
    
    const byProvider: { [key: string]: number } = {};
    const byModel: { [key: string]: number } = {};
    const byDay: { [date: string]: number } = {};

    relevantRecords.forEach(r => {
      byProvider[r.provider] = (byProvider[r.provider] || 0) + r.costUSD;
      byModel[r.model] = (byModel[r.model] || 0) + r.costUSD;
      
      const day = new Date(r.timestamp).toISOString().split('T')[0];
      byDay[day] = (byDay[day] || 0) + r.costUSD;
    });

    // Tính savings vs direct API
    const directCost = relevantRecords.reduce((sum, r) => {
      const directPrice = this.directPrices[r.model] || 0;
      return sum + (
        ((r.inputTokens + r.outputTokens) / 1000000) * directPrice
      );
    }, 0);

    const daysSoFar = (Date.now() - Math.min(...relevantRecords.map(r => r.timestamp))) / (24 * 60 * 60 * 1000);
    const projectedMonthly = daysSoFar > 0 ? (totalCost / daysSoFar) * 30 : totalCost;

    return {
      totalCost,
      byProvider,
      byModel,
      byDay,
      projectedMonthly,
      savingsVsDirect: directCost - totalCost
    };
  }

  // Real-time alert khi chi phí vượt ngưỡng
  async checkBudgetAlert(dailyLimit: number): Promise<{
    exceeded: boolean;
    todayCost: number;
    projectedToday: number;
  }> {
    const today = new Date().toISOString().split('T')[0];
    const todayRecords = this.records.filter(r => 
      new Date(r.timestamp).toISOString().split('T')[0] === today
    );
    
    const todayCost = todayRecords.reduce((sum, r) => sum + r.costUSD, 0);
    const hoursPassed = new Date().getHours() + 1;
    const projectedToday = (todayCost / hoursPassed) * 24;

    return {
      exceeded: todayCost > dailyLimit,
      todayCost,
      projectedToday
    };
  }
}

export { CostTracker, CostRecord, CostSummary };

Lỗi Thường Gặp và Cách Khắc Phục

1. Lỗi 429 Rate Limit - "Too Many Requests"

Mô tả lỗi: Request bị reject với status 429 khi vượt quá rate limit của provider.

// Fix: Implement proper rate limit handling với queue
class RateLimitHandler {
  private queue: Array<{
    request: any;
    resolve: Function;
    reject: Function;
    priority: number;
  }> = [];
  private processing: boolean = false;

  async execute(request: any, priority: number = 0): Promise<any> {
    return new Promise((resolve, reject) => {
      this.queue.push({ request