Class: Aidp::Harness::UsageLimitEnforcer

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/harness/usage_limit_enforcer.rb

Overview

Application service for enforcing usage limits Coordinates between UsageLimit config and UsageLimitTracker

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(provider_name:, usage_limit:, tracker:) ⇒ UsageLimitEnforcer

Initialize the enforcer with configuration

Parameters:

  • provider_name (String)

    Name of the provider

  • usage_limit (UsageLimit)

    Usage limit configuration

  • tracker (UsageLimitTracker)

    Tracker instance for usage data



70
71
72
73
74
75
76
77
78
79
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 70

def initialize(provider_name:, usage_limit:, tracker:)
  @provider_name = provider_name.to_s
  @usage_limit = usage_limit
  @tracker = tracker

  Aidp.log_debug("usage_limit_enforcer", "initialized",
    provider: @provider_name,
    enabled: @usage_limit.enabled?,
    period: @usage_limit.period)
end

Instance Attribute Details

#provider_nameObject (readonly)

Returns the value of attribute provider_name.



63
64
65
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 63

def provider_name
  @provider_name
end

#trackerObject (readonly)

Returns the value of attribute tracker.



63
64
65
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 63

def tracker
  @tracker
end

#usage_limitObject (readonly)

Returns the value of attribute usage_limit.



63
64
65
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 63

def usage_limit
  @usage_limit
end

Instance Method Details

#check_before_request(tier: "standard") ⇒ Object

Check if usage limits allow a request before making API call

Parameters:

  • tier (String) (defaults to: "standard")

    The tier for this request

Raises:



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 85

def check_before_request(tier: "standard")
  Aidp.log_debug("usage_limit_enforcer", "checking_limits",
    provider: @provider_name,
    tier: tier)

  return unless @usage_limit.enabled?

  current = @tracker.current_usage(
    period_type: @usage_limit.period,
    reset_day: @usage_limit.reset_day
  )

  limits = @usage_limit.limits_for_tier(tier)
  check_result = @usage_limit.exceeds_limit?(
    current_tokens: current[:total_tokens],
    current_cost: current[:total_cost],
    tier: tier
  )

  if check_result[:exceeded]
    Aidp.log_warn("usage_limit_enforcer", "limit_exceeded",
      provider: @provider_name,
      tier: tier,
      reason: check_result[:reason])

    raise UsageLimitExceededError.new(
      provider_name: @provider_name,
      tier: tier,
      current_tokens: current[:total_tokens],
      current_cost: current[:total_cost],
      max_tokens: limits[:max_tokens],
      max_cost: limits[:max_cost],
      period_description: current[:period_description]
    )
  end

  Aidp.log_debug("usage_limit_enforcer", "limits_ok",
    provider: @provider_name,
    tier: tier,
    tokens: current[:total_tokens],
    cost: current[:total_cost])
end

#check_headroom(additional_tokens: 0, additional_cost: 0.0, tier: "standard") ⇒ Hash

Check if limits would be exceeded by additional usage Non-raising version for checking without blocking

Parameters:

  • additional_tokens (Integer) (defaults to: 0)

    Additional tokens to add

  • additional_cost (Float) (defaults to: 0.0)

    Additional cost to add

  • tier (String) (defaults to: "standard")

    The tier to check

Returns:

  • (Hash)

    Result with :would_exceed and :headroom



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 152

def check_headroom(additional_tokens: 0, additional_cost: 0.0, tier: "standard")
  return {would_exceed: false, headroom: {tokens: nil, cost: nil}} unless @usage_limit.enabled?

  current = @tracker.current_usage(
    period_type: @usage_limit.period,
    reset_day: @usage_limit.reset_day
  )

  limits = @usage_limit.limits_for_tier(tier)

  projected_tokens = current[:total_tokens] + additional_tokens
  projected_cost = current[:total_cost] + additional_cost

  token_headroom = limits[:max_tokens] ? limits[:max_tokens] - current[:total_tokens] : nil
  cost_headroom = limits[:max_cost] ? limits[:max_cost] - current[:total_cost] : nil

  would_exceed = false
  would_exceed = true if limits[:max_tokens] && projected_tokens >= limits[:max_tokens]
  would_exceed = true if limits[:max_cost] && projected_cost >= limits[:max_cost]

  {
    would_exceed: would_exceed,
    headroom: {
      tokens: token_headroom,
      cost: cost_headroom
    },
    current: {
      tokens: current[:total_tokens],
      cost: current[:total_cost]
    },
    limits: limits
  }
end

#record_after_request(tokens:, cost:, tier: "standard") ⇒ Object

Record usage after a successful API request

Parameters:

  • tokens (Integer)

    Tokens used in the request

  • cost (Float)

    Cost of the request

  • tier (String) (defaults to: "standard")

    Tier used for the request



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 133

def record_after_request(tokens:, cost:, tier: "standard")
  return unless @usage_limit.enabled?

  @tracker.record_usage(
    tokens: tokens,
    cost: cost,
    tier: tier,
    period_type: @usage_limit.period,
    reset_day: @usage_limit.reset_day
  )
end

#usage_summaryHash

Get usage summary for display

Returns:

  • (Hash)

    Usage summary with current values, limits, and percentages



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/aidp/harness/usage_limit_enforcer.rb', line 189

def usage_summary
  return {enabled: false} unless @usage_limit.enabled?

  current = @tracker.current_usage(
    period_type: @usage_limit.period,
    reset_day: @usage_limit.reset_day
  )

  # Aggregate across common tiers
  tiers_summary = %w[mini standard advanced].map do |tier|
    limits = @usage_limit.limits_for_tier(tier)
    tier_usage = @tracker.tier_usage(
      tier: tier,
      period_type: @usage_limit.period,
      reset_day: @usage_limit.reset_day
    )

    {
      tier: tier,
      tokens: tier_usage[:tokens],
      cost: tier_usage[:cost],
      requests: tier_usage[:requests],
      max_tokens: limits[:max_tokens],
      max_cost: limits[:max_cost],
      token_percent: calculate_percent(tier_usage[:tokens], limits[:max_tokens]),
      cost_percent: calculate_percent(tier_usage[:cost], limits[:max_cost])
    }
  end

  {
    enabled: true,
    provider: @provider_name,
    period: @usage_limit.period,
    period_description: current[:period_description],
    total_tokens: current[:total_tokens],
    total_cost: current[:total_cost],
    total_requests: current[:request_count],
    remaining_seconds: current[:remaining_seconds],
    tiers: tiers_summary
  }
end