Overview
Version: v10.5.0 Scale & Reliability
Effort: M · 3–5 days
Branch: feature/s02-cost-gates
Add built-in guardrails to prevent runaway LLM costs and API rate-limit breaches. Two orthogonal mechanisms: cost gates (abort if estimated cost exceeds a cap) and rate limiters (throttle requests per provider per second/minute).
API Design
CouncilBuilder Extensions
// Hard cap: abort debate if estimated cost exceeds limit
councilBuilder.WithCostLimit(decimal maxUsd);
councilBuilder.WithCostLimit(decimal maxUsd, CostLimitBehavior behavior);
// behavior: Abort (default) | WarnAndContinue | PauseAndWait
// Rate limit: max N requests per window per provider
councilBuilder.WithRateLimit(int requestsPerMinute);
councilBuilder.WithRateLimit(int requestsPerMinute, TimeSpan window);
councilBuilder.WithRateLimit(RateLimitPolicy policy);
CostEstimate on DebateResult
public record CostEstimate
{
public decimal TotalUsd { get; init; }
public decimal InputUsd { get; init; }
public decimal OutputUsd { get; init; }
public IReadOnlyList<MemberCostBreakdown> ByMember { get; init; }
public string Currency { get; init; } // always "USD"
public bool IsEstimate { get; init; } // true when based on token prices, not actual billing
}
public record MemberCostBreakdown
{
public string Role { get; init; }
public string Model { get; init; }
public int InputTokens { get; init; }
public int OutputTokens { get; init; }
public decimal CostUsd { get; init; }
}
// DebateResult gains:
public CostEstimate? CostEstimate { get; init; }
RateLimitPolicy
public record RateLimitPolicy
{
public int RequestsPerWindow { get; init; }
public TimeSpan Window { get; init; } // default: 1 minute
public RateLimitScope Scope { get; init; } // PerProvider | PerModel | Global
public RateLimitBehavior Behavior { get; init; } // Queue | Throw | Drop
}
public enum RateLimitScope { PerProvider, PerModel, Global }
public enum RateLimitBehavior { Queue, Throw, Drop }
public enum CostLimitBehavior { Abort, WarnAndContinue, PauseAndWait }
Pricing Registry
public interface IModelPricingRegistry
{
ModelPricing? GetPricing(string provider, string model);
void Register(string provider, string model, decimal inputPer1kTokens, decimal outputPer1kTokens);
}
public record ModelPricing
{
public string Provider { get; init; }
public string Model { get; init; }
public decimal InputPer1KTokens { get; init; } // USD
public decimal OutputPer1KTokens { get; init; } // USD
public DateTime EffectiveDate { get; init; }
}
Built-in pricing for common models (GPT-4o, GPT-4o-mini, Claude 3.5 Sonnet, Claude 3 Haiku). Pricing registry is editable via appsettings.json:
"Delibera": {
"Pricing": {
"openai/gpt-4o": { "InputPer1K": 0.0025, "OutputPer1K": 0.01 },
"openai/gpt-4o-mini": { "InputPer1K": 0.00015, "OutputPer1K": 0.0006 },
"anthropic/claude-3-5-sonnet": { "InputPer1K": 0.003, "OutputPer1K": 0.015 }
}
}
Cost Gate Flow
Before each member turn:
1. Estimate tokens for next turn (context length + expected output)
2. Calculate incremental cost
3. Add to running total
4. If total > maxUsd:
- Abort → throw DebateCostLimitExceededException, save partial result
- Warn → log warning, continue
- Pause → checkpoint + raise DebatePausedEvent(reason: CostLimit)
Rate Limiter Flow
Before each LLM call:
1. Acquire slot from RateLimiter for (provider, model)
2. Queue → wait until slot available (respects WithTimeout)
3. Throw → throw DebateRateLimitExceededException
4. Drop → skip member turn, log warning
Implemented using System.Threading.RateLimiting.TokenBucketRateLimiter (built-in .NET 7+).
Tasks
Acceptance Criteria
Labels
enhancement, v10.5.0, reliability, cost
Overview
Version: v10.5.0 Scale & Reliability
Effort: M · 3–5 days
Branch:
feature/s02-cost-gatesAdd built-in guardrails to prevent runaway LLM costs and API rate-limit breaches. Two orthogonal mechanisms: cost gates (abort if estimated cost exceeds a cap) and rate limiters (throttle requests per provider per second/minute).
API Design
CouncilBuilder Extensions
CostEstimate on DebateResult
RateLimitPolicy
Pricing Registry
Built-in pricing for common models (GPT-4o, GPT-4o-mini, Claude 3.5 Sonnet, Claude 3 Haiku). Pricing registry is editable via
appsettings.json:Cost Gate Flow
Rate Limiter Flow
Implemented using
System.Threading.RateLimiting.TokenBucketRateLimiter(built-in .NET 7+).Tasks
IModelPricingRegistry+DefaultModelPricingRegistryCostEstimate+MemberCostBreakdownrecordsCostEstimatetoDebateResultCouncilExecutor(after each turn)WithCostLimit(...)toICouncilBuilder+CouncilBuilderRateLimitPolicyrecord + enumsDebateRateLimiterusingTokenBucketRateLimiterWithRateLimit(...)toICouncilBuilder+CouncilBuilderappsettings.jsoninDelibera.ServerCostEstimatetoDebateResponseDTO in serverdebate.cost_usdmetric gaugedocs/cost-gates.mdAcceptance Criteria
WithCostLimit(0.01m)aborts a debate that would exceed $0.01DebateResult.CostEstimateis populated for all debates with known pricingWithRateLimit(60)throttles to 60 requests/minute per providerRateLimitBehavior.Queuecorrectly delays requests without droppingappsettings.jsonand overrides built-in pricesdebate.cost_usdOpenTelemetry metric emitted after each debateWithCostLimitnorWithRateLimitis configured (zero overhead)Labels
enhancement,v10.5.0,reliability,cost