En tant qu'architecte backend qui a géré l'infrastructure IA de trois startups consecutively, j'ai confronté无数次 le même cauchemar : une équipe de data science qui siphonne tout le budget API pendant qu'un projet critique ralentit à mort. Ce n'est qu'en implémentant une gouvernance de quotas structurée que j'ai retrouvé la sérénité. Aujourd'hui, je vous partage ma recette complète pour maîtriser vos quotas HolySheep avec une isolation granulaire, des stratégies de rate limiting intelligentes, et un système d'alertes proactives.

Architecture de Gouvernance HolySheep : Vue d'Ensemble

HolySheep propose une architecture de quotas hiérarchique qui reflète exactement la structure organisationnelle d'une entreprise moderne. Le système supporte trois niveaux de nesting : Organization → Projects → Teams, avec une granularité descendante qui permet des héritages et overrides intelligentes.

{
  "organization": {
    "id": "org_acme_corp",
    "name": "Acme Corporation",
    "global_monthly_limit": 5000000,
    "quota_currency": "USD",
    "children": {
      "projects": {
        "prod_api": {
          "monthly_budget": 2000000,
          "priority": "critical",
          "children": {
            "teams": {
              "frontend_team": {
                "rate_limit_rpm": 500,
                "daily_quota": 50000,
                "token_budget_monthly": 800000
              },
              "ml_team": {
                "rate_limit_rpm": 1000,
                "daily_quota": 150000,
                "token_budget_monthly": 1200000
              }
            }
          }
        },
        "dev_sandbox": {
          "monthly_budget": 50000,
          "priority": "low",
          "rate_limit_rpm": 50
        }
      }
    },
    "cross_team_policies": {
      "fair_share_enabled": true,
      "burst_allowance_percent": 20,
      "overage_behavior": "queue_priority"
    }
  }
}

Cette configuration montre la puissance du système : le projet prod_api dispose de 2M tokens/mois contre seulement 50K pour le sandbox dev. Les équipes au sein du projet ont des quotas distincts, et la politique fair_share_enabled assure qu'aucune équipe ne peut monopoliser les ressources communes.

Configuration SDK : Intégration Python Niveau Production

Passons au code concret. Voici ma configuration SDK éprouvée avec gestion automatique des quotas et retry exponentiel :

#!/usr/bin/env python3
"""
HolySheep Quota-Aware Client
Architecture multi-équipes avec isolation et monitoring intégré
"""

import os
import time
import asyncio
import logging
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List
from dataclasses import dataclass, field
from collections import defaultdict
from threading import Lock
import requests

Configuration HolySheep - OBLIGATOIRE : utiliser api.holysheep.ai

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" API_KEY = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") @dataclass class QuotaMetrics: """Métriques de quota en temps réel""" team_id: str requests_today: int = 0 tokens_consumed: int = 0 tokens_limit: int daily_limit: int rpm_current: int = 0 rpm_limit: int last_reset: datetime = field(default_factory=datetime.utcnow) def usage_percent(self) -> float: return (self.tokens_consumed / self.tokens_limit) * 100 def daily_usage_percent(self) -> float: return (self.requests_today / self.daily_limit) * 100 class HolySheepQuotaClient: """ Client HolySheep avec gouvernance de quotas intégrée. Gère l'isolation inter-équipes, le rate limiting, et les alertes. """ def __init__( self, api_key: str, base_url: str = HOLYSHEEP_BASE_URL, team_id: str = "default", quota_metrics: Optional[QuotaMetrics] = None ): self.api_key = api_key self.base_url = base_url.rstrip('/') self.team_id = team_id self.headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "X-Team-ID": team_id, "X-Request-ID": f"{team_id}_{int(time.time()*1000)}" } # Rate limiting interne self._rate_limit_lock = Lock() self._request_timestamps: List[float] = [] self.rpm_limit = 1000 self.min_request_interval = 60 / self.rpm_limit # Monitoring self._metrics = quota_metrics or QuotaMetrics( team_id=team_id, tokens_limit=1_000_000, daily_limit=50_000, rpm_limit=1000 ) # Configuration alertes (seuils personnalisables) self.alert_thresholds = { "quota_80_percent": True, "quota_95_percent": True, "rate_limit_hit": True, "error_spike": True } self.logger = logging.getLogger(f"HolySheep.{team_id}") def _check_rate_limit(self) -> bool: """Vérifie et applique le rate limiting interne""" with self._rate_limit_lock: now = time.time() # Supprimer les requêtes de plus d'1 minute self._request_timestamps = [ ts for ts in self._request_timestamps if now - ts < 60 ] if len(self._request_timestamps) >= self.rpm_limit: sleep_time = 60 - (now - self._request_timestamps[0]) if sleep_time > 0: self.logger.warning( f"Rate limit atteint pour {self.team_id}. " f"Attente {sleep_time:.2f}s" ) time.sleep(sleep_time) self._request_timestamps.append(now) return True def _update_metrics( self, tokens_used: int, request_success: bool ) -> None: """Met à jour les métriques de consommation""" self._metrics.tokens_consumed += tokens_used if request_success: self._metrics.requests_today += 1 # Vérifier seuils d'alerte self._check_alert_thresholds() def _check_alert_thresholds(self) -> None: """Déclenche des alertes selon les seuils configurés""" usage = self._metrics.usage_percent() daily_usage = self._metrics.daily_usage_percent() if usage >= 95 and self.alert_thresholds["quota_95_percent"]: self._send_alert( level="CRITICAL", message=f"⚠️ {self.team_id}: Quota à 95% ({usage:.1f}%)" ) elif usage >= 80 and self.alert_thresholds["quota_80_percent"]: self._send_alert( level="WARNING", message=f"🔔 {self.team_id}: Quota à 80% ({usage:.1f}%)" ) def _send_alert(self, level: str, message: str) -> None: """Envoie une alerte (Webhook, Slack, etc.)""" self.logger.critical(message) # Intégration webhook configurable # webhook_url = os.environ.get("ALERT_WEBHOOK_URL") # if webhook_url: # requests.post(webhook_url, json={"text": f"[{level}] {message}"}) def chat_completions( self, model: str, messages: List[Dict], max_tokens: int = 1000, temperature: float = 0.7, **kwargs ) -> Dict[str, Any]: """ Appel API avec gestion quota intégrée. Args: model: Modèle HolySheep (gpt-4.1, claude-sonnet-4.5, etc.) messages: Messages au format OpenAI max_tokens: Limite de tokens de réponse temperature: Créativité du modèle Returns: Réponse API avec métriques enrichies """ self._check_rate_limit() endpoint = f"{self.base_url}/chat/completions" payload = { "model": model, "messages": messages, "max_tokens": max_tokens, "temperature": temperature, **kwargs } start_time = time.time() try: response = requests.post( endpoint, headers=self.headers, json=payload, timeout=30 ) latency_ms = (time.time() - start_time) * 1000 if response.status_code == 200: result = response.json() usage = result.get("usage", {}) tokens_used = usage.get("total_tokens", 0) self._update_metrics(tokens_used, True) # Ajouter métadonnées de monitoring result["_quota_metadata"] = { "team_id": self.team_id, "tokens_used": tokens_used, "latency_ms": round(latency_ms, 2), "quota_remaining": self._metrics.tokens_limit - self._metrics.tokens_consumed, "timestamp": datetime.utcnow().isoformat() } self.logger.info( f"✓ {self.team_id} | {model} | " f"{tokens_used} tokens | {latency_ms:.0f}ms" ) return result elif response.status_code == 429: self._send_alert("WARNING", "Rate limit atteint (HTTP 429)") raise QuotaExceededError( f"Rate limit atteint pour {self.team_id}" ) elif response.status_code == 400: self.logger.error(f"Erreur 400: {response.text}") raise APIError(f"Bad request: {response.text}") else: self.logger.error( f"Erreur API: {response.status_code} - {response.text}" ) raise APIError(f"API error: {response.status_code}") except requests.exceptions.Timeout: self.logger.error("Timeout lors de l'appel API HolySheep") raise APIError("Request timeout") def get_quota_status(self) -> Dict[str, Any]: """Retourne le statut actuel des quotas pour cette équipe""" return { "team_id": self.team_id, "tokens_consumed": self._metrics.tokens_consumed, "tokens_limit": self._metrics.tokens_limit, "usage_percent": round(self._metrics.usage_percent(), 2), "requests_today": self._metrics.requests_today, "daily_limit": self._metrics.daily_limit, "daily_usage_percent": round(self._metrics.daily_usage_percent(), 2), "rpm_current": len(self._request_timestamps), "rpm_limit": self.rpm_limit, "last_reset": self._metrics.last_reset.isoformat() } class QuotaExceededError(Exception): """Exception levée quand le quota est épuisé""" pass class APIError(Exception): """Exception générale pour erreurs API""" pass

============================================================

EXEMPLE D'UTILISATION MULTI-ÉQUIPES

============================================================

def create_team_clients() -> Dict[str, HolySheepQuotaClient]: """ Fabrique les clients pour différentes équipes avec quotas spécifiques. """ clients = {} team_configs = { "frontend": { "quota_metrics": QuotaMetrics( team_id="frontend", tokens_limit=800_000, daily_limit=50_000, rpm_limit=500 ) }, "backend": { "quota_metrics": QuotaMetrics( team_id="backend", tokens_limit=1_000_000, daily_limit=75_000, rpm_limit=800 ) }, "ml_ops": { "quota_metrics": QuotaMetrics( team_id="ml_ops", tokens_limit=2_000_000, daily_limit=150_000, rpm_limit=1500 ) } } for team_id, config in team_configs.items(): clients[team_id] = HolySheepQuotaClient( api_key=API_KEY, team_id=team_id, quota_metrics=config["quota_metrics"] ) return clients if __name__ == "__main__": logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s: %(message)s" ) # Créer les clients pour chaque équipe team_clients = create_team_clients() # Exemple d'appel pour l'équipe frontend frontend_client = team_clients["frontend"] messages = [ {"role": "system", "content": "Tu es un assistant utile."}, {"role": "user", "content": "Explique-moi les quotas HolySheep en 2 phrases."} ] try: response = frontend_client.chat_completions( model="gpt-4.1", messages=messages, max_tokens=150 ) print(f"Réponse: {response['choices'][0]['message']['content']}") print(f"Quota status: {frontend_client.get_quota_status()}") except QuotaExceededError as e: print(f"Quota épuisé: {e}") except APIError as e: print(f"Erreur API: {e}")

Stratégies Avancées de Rate Limiting

Token Bucket avec Priorités Multi-Niveaux

Ma configuration préférée pour les environnements multi-équipes est le token bucket avec priorités. Cette approche permet des bursts contrôlés tout en garantissant un floor de service pour les requêtes critiques :

#!/usr/bin/env python3
"""
HolySheep Advanced Rate Limiter - Token Bucket Multi-Niveaux
 with Priority Queuing and Cost-Aware Scheduling
"""

import time
import asyncio
from typing import Optional, Dict, Tuple
from enum import IntEnum
from dataclasses import dataclass, field
from collections import deque
import heapq
import threading

class RequestPriority(IntEnum):
    """Priorités de requêtes - plus le nombre est élevé, plus c'est prioritaire"""
    BACKGROUND = 0      # Batch processing, pas urgent
    NORMAL = 50         # Utilisation standard
    HIGH = 75           # Utilisateurs payants
    CRITICAL = 100      # Pannes, sécurité, SLA critiques

@dataclass(order=True)
class QueuedRequest:
    """Requête en file d'attente avec priorité"""
    priority: int = field(compare=True)
    arrival_time: float = field(compare=True)
    sequence: int = field(compare=True, default=0)
    team_id: str = field(compare=False, default="")
    tokens_estimate: int = field(compare=False, default=1000)
    callback: Optional[callable] = field(compare=False, default=None)
    metadata: Dict = field(compare=False, default_factory=dict)

class TokenBucketRateLimiter:
    """
    Rate limiter avancé avec:
    - Token bucket par équipe
    - Burst allowance configurable
    - Priorités multi-niveaux
    - Coût par modèle (en tokens)
    """
    
    def __init__(
        self,
        rpm_limit: int,
        burst_allowance: float = 1.5,
        refill_rate: float = 1.0
    ):
        """
        Args:
            rpm_limit: Requêtes par minute autorisées
            burst_allowance: Multiplicateur de burst (1.5 = 50% de burst)
            refill_rate: Taux de replenishment (1.0 = normal)
        """
        self.rpm_limit = rpm_limit
        self.max_tokens = int(rpm_limit * burst_allowance)
        self.tokens = float(self.max_tokens)
        self.refill_rate = refill_rate
        self.last_refill = time.time()
        
        # Tracking par équipe
        self.team_buckets: Dict[str, Dict] = {}
        self.team_limits = {
            "frontend": 500,
            "backend": 800,
            "ml_ops": 1500,
            "analytics": 200
        }
        
        # File prioritaire globale
        self.priority_queue: list = []
        self.sequence_counter = 0
        self.queue_lock = threading.Lock()
        
        # Monitoring
        self.total_requests = 0
        self.rejected_requests = 0
        self.queued_requests = 0
        
    def _refill_tokens(self) -> None:
        """Recharge les tokens selon le temps écoulé"""
        now = time.time()
        elapsed = now - self.last_refill
        tokens_to_add = elapsed * (self.rpm_limit / 60.0) * self.refill_rate
        
        self.tokens = min(self.max_tokens, self.tokens + tokens_to_add)
        self.last_refill = now
    
    def _check_team_limit(self, team_id: str) -> bool:
        """Vérifie la limite spécifique à l'équipe"""
        if team_id not in self.team_buckets:
            # Initialiser le bucket de l'équipe
            team_limit = self.team_limits.get(team_id, 100)
            self.team_buckets[team_id] = {
                "tokens": team_limit,
                "last_request": 0,
                "requests_this_minute": 0,
                "window_start": time.time()
            }
        
        team = self.team_buckets[team_id]
        team_limit = self.team_limits.get(team_id, 100)
        
        # Reset le compteur si nouvelle minute
        if time.time() - team["window_start"] >= 60:
            team["requests_this_minute"] = 0
            team["window_start"] = time.time()
        
        # Vérifier si limite team atteinte
        if team["requests_this_minute"] >= team_limit:
            return False
        
        return True
    
    def acquire(
        self,
        team_id: str,
        tokens_cost: int = 1,
        priority: RequestPriority = RequestPriority.NORMAL,
        timeout: float = 30.0,
        model: str = "gpt-4.1"
    ) -> Tuple[bool, Optional[str]]:
        """
        Tente d'acquérir un slot pour exécuter une requête.
        
        Args:
            team_id: Identifiant de l'équipe
            tokens_cost: Nombre de tokens à "consommer"
            priority: Priorité de la requête
            timeout: Timeout maximum en secondes
            model: Modèle pour estimer le coût
            
        Returns:
            (success, message)
        """
        self._refill_tokens()
        
        deadline = time.time() + timeout
        
        while time.time() < deadline:
            # Vérifier limite globale
            if self.tokens >= tokens_cost:
                # Vérifier limite équipe
                if self._check_team_limit(team_id):
                    self.tokens -= tokens_cost
                    self.total_requests += 1
                    
                    # Mettre à jour stats équipe
                    team = self.team_buckets[team_id]
                    team["requests_this_minute"] += 1
                    team["last_request"] = time.time()
                    
                    return True, f"Acquis ({self.tokens:.1f} tokens restants)"
            
            # File d'attente avec priorité
            with self.queue_lock:
                request = QueuedRequest(
                    priority=priority,
                    arrival_time=time.time(),
                    sequence=self.sequence_counter,
                    team_id=team_id,
                    tokens_estimate=tokens_cost
                )
                self.sequence_counter += 1
                self.queued_requests += 1
                heapq.heappush(self.priority_queue, request)
            
            # Attente active avec backoff exponentiel
            wait_time = min(0.5 * (1.5 ** (self.queued_requests % 5)), 5.0)
            time.sleep(min(wait_time, deadline - time.time()))
        
        self.rejected_requests += 1
        return False, f"Timeout après {timeout}s - Quota indisponible"
    
    def get_status(self) -> Dict:
        """Retourne le statut complet du rate limiter"""
        return {
            "global_tokens": round(self.tokens, 2),
            "max_tokens": self.max_tokens,
            "utilization_percent": round(
                (1 - self.tokens/self.max_tokens) * 100, 2
            ),
            "total_requests": self.total_requests,
            "rejected_requests": self.rejected_requests,
            "queued_requests": len(self.priority_queue),
            "rejection_rate_percent": round(
                self.rejected_requests / max(1, self.total_requests) * 100, 2
            ),
            "teams": {
                team_id: {
                    "tokens": round(data["tokens"], 2),
                    "requests_this_minute": data["requests_this_minute"],
                    "limit": self.team_limits.get(team_id, 100)
                }
                for team_id, data in self.team_buckets.items()
            }
        }


class QuotaManager:
    """
    Gestionnaire centralisé des quotas multi-équipes.
    Coordonne les limites, les alertes, et les policies de surcharge.
    """
    
    # Coût en tokens par modèle (entrée + sortie estimés)
    MODEL_COSTS = {
        "gpt-4.1": 15,           # $8/1M tokens
        "claude-sonnet-4.5": 27, # $15/1M tokens  
        "gemini-2.5-flash": 4.5, # $2.50/1M tokens
        "deepseek-v3.2": 0.75,   # $0.42/1M tokens
        "gpt-4o-mini": 3,        # $1.50/1M tokens
    }
    
    def __init__(self, monthly_budget_usd: float):
        self.monthly_budget_usd = monthly_budget_usd
        self.total_spent_usd = 0.0
        
        # Ratio HolySheep: ¥1 = $1 (économie 85%+)
        self.exchange_rate = 1.0
        self.effective_budget = monthly_budget_usd
        
        # Trackers par équipe
        self.team_spending: Dict[str, float] = defaultdict(float)
        self.team_limits_usd: Dict[str, float] = {
            "frontend": 500,
            "backend": 800,
            "ml_ops": 2000,
            "analytics": 200
        }
        
        # Rate limiters par équipe
        self.rate_limiters: Dict[str, TokenBucketRateLimiter] = {
            team: TokenBucketRateLimiter(rpm_limit=limits)
            for team, limits in {
                "frontend": 500,
                "backend": 800,
                "ml_ops": 1500,
                "analytics": 200
            }.items()
        }
        
        # Seuils d'alerte (%)
        self.alert_thresholds = {
            "warning": 70,
            "critical": 85,
            "emergency": 95
        }
    
    def estimate_cost(
        self,
        model: str,
        input_tokens: int,
        output_tokens: int
    ) -> float:
        """Estime le coût en USD d'une requête"""
        cost_per_1k = self.MODEL_COSTS.get(model, 15)
        total_tokens = input_tokens + output_tokens
        return (total_tokens / 1000) * (cost_per_1k / 1000)
    
    def check_budget(
        self,
        team_id: str,
        estimated_cost: float
    ) -> Tuple[bool, str]:
        """
        Vérifie si le budget est disponible pour une équipe.
        
        Returns:
            (approved, reason)
        """
        # Vérifier budget global
        if self.total_spent_usd + estimated_cost > self.effective_budget:
            return False, "Budget global épuisé"
        
        # Vérifier budget équipe
        team_limit = self.team_limits_usd.get(team_id, 200)
        if self.team_spending[team_id] + estimated_cost > team_limit:
            return False, f"Budget équipe {team_id} épuisé ({team_limit}$)"
        
        # Vérifier seuils d'alerte
        global_usage = (self.total_spent_usd / self.effective_budget) * 100
        
        if global_usage >= self.alert_thresholds["emergency"]:
            self._trigger_emergency_alert(team_id, global_usage)
        elif global_usage >= self.alert_thresholds["critical"]:
            self._trigger_critical_alert(team_id, global_usage)
        elif global_usage >= self.alert_thresholds["warning"]:
            self._trigger_warning_alert(team_id, global_usage)
        
        return True, "OK"
    
    def record_usage(
        self,
        team_id: str,
        model: str,
        input_tokens: int,
        output_tokens: int,
        actual_cost_usd: float
    ) -> None:
        """Enregistre l'utilisation réelle et met à jour les compteurs"""
        self.total_spent_usd += actual_cost_usd
        self.team_spending[team_id] += actual_cost_usd
        
        print(f"📊 [{team_id}] {model} | "
              f"{input_tokens}+{output_tokens} tokens | "
              f"{actual_cost_usd:.4f}$ | "
              f"Total équipe: {self.team_spending[team_id]:.2f}$ | "
              f"Global: {self.total_spent_usd:.2f}$")
    
    def _trigger_emergency_alert(self, team_id: str, usage: float) -> None:
        print(f"🚨 ALERTE URGENCE [{team_id}] Budget à {usage:.1f}%")
        # Envoyer notification d'urgence
    
    def _trigger_critical_alert(self, team_id: str, usage: float) -> None:
        print(f"🔴 ALERTE CRITIQUE [{team_id}] Budget à {usage:.1f}%")
    
    def _trigger_warning_alert(self, team_id: str, usage: float) -> None:
        print(f"🟡 AVERTISSEMENT [{team_id}] Budget à {usage:.1f}%")


============================================================

EXEMPLE D'UTILISATION

============================================================

if __name__ == "__main__": # Initialiser le gestionnaire de quotas quota_manager = QuotaManager(monthly_budget_usd=5000) # Scénario: Requête de l'équipe ML Ops team_id = "ml_ops" model = "deepseek-v3.2" # Modèle économique HolySheep input_tokens = 500 output_tokens = 300 # 1. Estimer le coût estimated_cost = quota_manager.estimate_cost( model, input_tokens, output_tokens ) print(f"Coût estimé: {estimated_cost:.4f}$") # 2. Vérifier budget disponible approved, reason = quota_manager.check_budget(team_id, estimated_cost) print(f"Budget check: {approved} - {reason}") if approved: # 3. Acquérir un slot rate limiting limiter = quota_manager.rate_limiters[team_id] acquired, msg = limiter.acquire( team_id=team_id, tokens_cost=1, priority=RequestPriority.NORMAL ) print(f"Rate limit: {acquired} - {msg}") if acquired: # 4. Simuler l'appel API (dans la réalité, appeler HolySheep) print(f"→ Appel HolySheep API: {model}") # 5. Enregistrer l'utilisation quota_manager.record_usage( team_id, model, input_tokens, output_tokens, estimated_cost ) # Afficher statut complet print("\n📈 STATUT QUOTA MANAGER:") print(f"Total dépensé: {quota_manager.total_spent_usd:.2f}$") print(f"Budget restant: {quota_manager.effective_budget - quota_manager.total_spent_usd:.2f}$") for team, limiter in quota_manager.rate_limiters.items(): print(f"\n{team}:") print(f" {limiter.get_status()}")

Système d'Alertes et Monitoring en Temps Réel

Un système de gouvernance sans monitoring est comme conduire les yeux fermés. Voici ma configuration d'alertes complète avec seuils personnalisables et intégrations multiples :

#!/usr/bin/env python3
"""
HolySheep Quota Alert System - Monitoring et Notifications
Webhook, Slack, PagerDuty, Email, WeChat/Alipay support
"""

import os
import time
import json
import threading
import smtplib
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Callable
from dataclasses import dataclass, field
from enum import Enum
from collections import deque
import requests

class AlertLevel(Enum):
    INFO = "info"
    WARNING = "warning"
    CRITICAL = "critical"
    EMERGENCY = "emergency"

@dataclass
class Alert:
    """Structure d'une alerte"""
    level: AlertLevel
    team_id: str
    message: str
    metric_name: str
    current_value: float
    threshold: float
    timestamp: datetime = field(default_factory=datetime.utcnow)
    metadata: Dict = field(default_factory=dict)

class AlertChannel:
    """Interface pour les canaux d'alerte"""
    
    def send(self, alert: Alert) -> bool:
        raise NotImplementedError

class SlackWebhookChannel(AlertChannel):
    """Canal Slack avec formatage enrichi"""
    
    def __init__(self, webhook_url: str, channel: str = "#alerts"):
        self.webhook_url = webhook_url
        self.channel = channel
    
    def send(self, alert: Alert) -> bool:
        colors = {
            AlertLevel.INFO: "#36a64f",
            AlertLevel.WARNING: "#ff9800", 
            AlertLevel.CRITICAL: "#f44336",
            AlertLevel.EMERGENCY: "#9c27b0"
        }
        
        payload = {
            "channel": self.channel,
            "attachments": [{
                "color": colors.get(alert.level, "#808080"),
                "title": f"🚨 Alerte HolySheep [{alert.level.value.upper()}]",
                "text": alert.message,
                "fields": [
                    {"title": "Équipe", "value": alert.team_id, "short": True},
                    {"title": "Métrique", "value": alert.metric_name, "short": True},
                    {"title": "Valeur actuelle", "value": f"{alert.current_value:.1f}%", "short": True},
                    {"title": "Seuil", "value": f"{alert.threshold:.1f}%", "short": True},
                ],
                "footer": "HolySheep Quota Monitor",
                "ts": alert.timestamp.timestamp()
            }]
        }
        
        try:
            response = requests.post(self.webhook_url, json=payload, timeout=10)
            return response.status_code == 200
        except Exception as e:
            print(f"Erreur envoi Slack: {e}")
            return False

class WebhookChannel(AlertChannel):
    """Canal webhook générique pour intégrations personnalisées"""
    
    def __init__(self, webhook_url: str, headers: Dict = None):
        self.webhook_url = webhook_url
        self.headers = headers or {"Content-Type": "application/json"}
    
    def send(self, alert: Alert) -> bool:
        payload = {
            "level": alert.level.value,
            "team_id": alert.team_id,
            "message": alert.message,
            "metric_name": alert.metric_name,
            "current_value": alert.current_value,
            "threshold": alert.threshold,
            "timestamp": alert.timestamp.isoformat(),
            "metadata": alert.metadata
        }
        
        try:
            response = requests.post(
                self.webhook_url,
                json=payload,
                headers=self.headers,
                timeout=10
            )
            return response.status_code in (200, 201, 202, 204)
        except Exception as e:
            print(f"Erreur envoi webhook: {e}")
            return False

class EmailChannel(AlertChannel):
    """Canal Email pour alertes critiques"""
    
    def __init__(
        self,
        smtp_host: str,
        smtp_port: int,
        smtp_user: str,
        smtp_password: str,
        from_addr: str,
        to_addrs: List[str]
    ):
        self.smtp_host = smtp_host
        self.smtp_port = smtp_port
        self.smtp_user = smtp_user
        self.smtp_password = smtp_password
        self.from_addr = from_addr
        self.to_addrs = to_addrs
    
    def send(self, alert: Alert) -> bool:
        if alert.level not in (AlertLevel.CRITICAL, AlertLevel.EMERGENCY):
            return True  # Email uniquement pour critiques
        
        subject = f"[{alert.level.value.upper()}] HolySheep Alert - {alert.team_id}"
        body = f"""
HolySheep Quota Alert
=====================

Level: {alert.level.value.upper()}
Team: {alert.team_id}
Time: {alert.timestamp.strftime('%Y-%m-%d %H:%M:%S UTC')}

Message:
{alert.message}

Details:
- Metric: {alert.metric_name}
- Current Value: {alert.current_value:.1f}%
- Threshold: {alert.threshold:.1f}%

--
HolySheep AI Quota Monitoring
        """
        
        try:
            with smtplib.SMTP(self.smtp_host, self.smtp_port) as server:
                server.starttls()
                server.login(self.smtp_user, self.smtp_password)
                
                msg = f"From: {self.from_addr}\n"
                msg += f"To: {', '.join(self.to_addrs)}\n"
                msg += f"Subject: {subject}\n\n{body}"
                
                server.sendmail(self.from_addr, self.to_addrs, msg)
            return True
        except Exception as e:
            print(f"Erreur envoi email: {e}")
            return False

class QuotaAlertManager:
    """
    Gestionnaire centralisé des alertes de quota.
    Surveille les seuils et notifie via plusieurs canaux.
    """
    
    def __init__(self):
        self.channels: List[AlertChannel] = []
        self.alert_history: deque = deque(maxlen=1000)
        self.alert_cooldowns: Dict[str, datetime] = {}  # Éviter les spams
        
        # Seuils par défaut (%)
        self.default_thresholds = {
            "quota_usage_80": 80.0,
            "quota_usage_90": 90.0,
            "quota_usage_95": 95.0,
            "quota_usage_99": 99.0,
            "rate_limit_hit": 10,  # Nb de 429 par heure
            "error_rate": 5.0,  # % d'erreurs
            "latency_p99": 2000,  # ms
            "cost_budget_80": 80.0,
        }
        
        self.team_thresholds: Dict[str, Dict] = {}
        
        # Callbacks d'actions automatisées
        self.auto_actions: Dict[str, List[Callable]] = {
            "quota_95": [],  # Actions quand quota à 95%
            "rate_limit_exceeded