ask-llm-providers 0.13.7 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 702da6909b940ff6695187cda4e588bd047a2c7d8edbaabd1c037ff68dcedc6b
4
- data.tar.gz: 363641a625952797604bd8bb2fc3e3089819ce8cdd89a1d20f8c030092e828e0
3
+ metadata.gz: 1d97e79228f15d501abab8d4569ca8c5c5faf94d086ee4a4604209739ef1ce73
4
+ data.tar.gz: d8b980e5ad87e0b2a5bad0ea78ccc8f3c688a34baa5d02903d6a9fb422bcdf86
5
5
  SHA512:
6
- metadata.gz: 13253c6eed671a1159c349dafbb2bab8138725b55d07664aaf4ac60956bc42a4930df14cce7cb9f8212413b8b4447c8b4de5aefc1163a4f5aa704b590ab0247f
7
- data.tar.gz: bbeca3575d85b2f45d54f7602f12d8453488e1fd30302516d1bd9622ba8b24d20ef04ce0fe6effd9b2f06e33cade84a0b995480aa41d3c11e5e06f24eb28dfeb
6
+ metadata.gz: 96cdc8251cc3c4554b79ef0af7c7d3e9737ca2107980eb6757dd2077a8240147e0ebada7e68becf87bc05d582c4708d6a2ad06f4c15d52e1335b6f6fc7c1be89
7
+ data.tar.gz: 7e85861afa257bb7746d22c7c796796dbfcb63ff0d5f3bda6750fdf1fe11071ce851e37dd2821e72bbbe1dd2f2b2fc59b3f734499b332a089f2466a1bec1b9d8
@@ -98,12 +98,58 @@ module Ask
98
98
  result
99
99
  end
100
100
 
101
+ # Which pricing tier applies at a given moment.
102
+ #
103
+ # Providers bill some models at a higher rate during peak windows
104
+ # (Command Code doubles the DeepSeek V4 family on weekday mornings).
105
+ # A model with no +peak_schedule+ in its metadata always bills at
106
+ # :standard. Windows are UTC.
107
+ #
108
+ # CostCalculator.tier_at(model) # now
109
+ # CostCalculator.tier_at(model, at: Time.utc(2026, 9, 14, 7)) # => :peak
110
+ #
111
+ # @return [Symbol] :peak or :standard
112
+ def tier_at(model, at: Time.now)
113
+ schedule = extract_metadata(model)["peak_schedule"]
114
+ return :standard unless schedule.is_a?(Array) && schedule.any?
115
+
116
+ moment = at.getutc
117
+ day = moment.strftime("%a").downcase
118
+ minute = (moment.hour * 60) + moment.min
119
+
120
+ in_window = schedule.any? do |window|
121
+ next false unless Array(window["days"]).map { |d| d.to_s.downcase }.include?(day)
122
+
123
+ from = clock_minutes(window["from"])
124
+ to = clock_minutes(window["to"])
125
+ next false unless from && to
126
+
127
+ minute >= from && minute < to
128
+ end
129
+
130
+ in_window ? :peak : :standard
131
+ end
132
+
101
133
  private
102
134
 
103
135
  def extract_pricing(model)
104
136
  model.respond_to?(:pricing) ? model.pricing : model
105
137
  end
106
138
 
139
+ def extract_metadata(model)
140
+ return model.metadata || {} if model.respond_to?(:metadata)
141
+
142
+ model.is_a?(Hash) ? (model[:metadata] || model["metadata"] || {}) : {}
143
+ end
144
+
145
+ # "06:00" => 360
146
+ def clock_minutes(value)
147
+ match = value.to_s.match(/\A(\d{1,2}):(\d{2})\z/)
148
+ return nil unless match
149
+
150
+ (match[1].to_i * 60) + match[2].to_i
151
+ end
152
+
107
153
  def cost(tokens, rate)
108
154
  return 0.0 unless rate && tokens > 0
109
155
  (tokens * rate) / MILLION.to_f
@@ -5222,7 +5222,33 @@
5222
5222
  }
5223
5223
  },
5224
5224
  "metadata": {
5225
- "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak"
5225
+ "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak",
5226
+ "peak_schedule": [
5227
+ {
5228
+ "days": [
5229
+ "mon",
5230
+ "tue",
5231
+ "wed",
5232
+ "thu",
5233
+ "fri"
5234
+ ],
5235
+ "from": "01:00",
5236
+ "to": "04:00",
5237
+ "zone": "UTC"
5238
+ },
5239
+ {
5240
+ "days": [
5241
+ "mon",
5242
+ "tue",
5243
+ "wed",
5244
+ "thu",
5245
+ "fri"
5246
+ ],
5247
+ "from": "06:00",
5248
+ "to": "10:00",
5249
+ "zone": "UTC"
5250
+ }
5251
+ ]
5226
5252
  }
5227
5253
  },
5228
5254
  {
@@ -5257,7 +5283,33 @@
5257
5283
  }
5258
5284
  },
5259
5285
  "metadata": {
5260
- "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak"
5286
+ "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak",
5287
+ "peak_schedule": [
5288
+ {
5289
+ "days": [
5290
+ "mon",
5291
+ "tue",
5292
+ "wed",
5293
+ "thu",
5294
+ "fri"
5295
+ ],
5296
+ "from": "01:00",
5297
+ "to": "04:00",
5298
+ "zone": "UTC"
5299
+ },
5300
+ {
5301
+ "days": [
5302
+ "mon",
5303
+ "tue",
5304
+ "wed",
5305
+ "thu",
5306
+ "fri"
5307
+ ],
5308
+ "from": "06:00",
5309
+ "to": "10:00",
5310
+ "zone": "UTC"
5311
+ }
5312
+ ]
5261
5313
  }
5262
5314
  },
5263
5315
  {
@@ -5321,7 +5373,33 @@
5321
5373
  }
5322
5374
  },
5323
5375
  "metadata": {
5324
- "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak"
5376
+ "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak",
5377
+ "peak_schedule": [
5378
+ {
5379
+ "days": [
5380
+ "mon",
5381
+ "tue",
5382
+ "wed",
5383
+ "thu",
5384
+ "fri"
5385
+ ],
5386
+ "from": "01:00",
5387
+ "to": "04:00",
5388
+ "zone": "UTC"
5389
+ },
5390
+ {
5391
+ "days": [
5392
+ "mon",
5393
+ "tue",
5394
+ "wed",
5395
+ "thu",
5396
+ "fri"
5397
+ ],
5398
+ "from": "06:00",
5399
+ "to": "10:00",
5400
+ "zone": "UTC"
5401
+ }
5402
+ ]
5325
5403
  }
5326
5404
  },
5327
5405
  {
@@ -5356,7 +5434,33 @@
5356
5434
  }
5357
5435
  },
5358
5436
  "metadata": {
5359
- "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak"
5437
+ "peak_windows": "Mon-Fri 01:00-04:00 and 06:00-10:00 UTC bill at 2x (peak tier); weekends are fully off-peak",
5438
+ "peak_schedule": [
5439
+ {
5440
+ "days": [
5441
+ "mon",
5442
+ "tue",
5443
+ "wed",
5444
+ "thu",
5445
+ "fri"
5446
+ ],
5447
+ "from": "01:00",
5448
+ "to": "04:00",
5449
+ "zone": "UTC"
5450
+ },
5451
+ {
5452
+ "days": [
5453
+ "mon",
5454
+ "tue",
5455
+ "wed",
5456
+ "thu",
5457
+ "fri"
5458
+ ],
5459
+ "from": "06:00",
5460
+ "to": "10:00",
5461
+ "zone": "UTC"
5462
+ }
5463
+ ]
5360
5464
  }
5361
5465
  },
5362
5466
  {
@@ -14873,4 +14977,4 @@
14873
14977
  "pricing": {},
14874
14978
  "created_at": "2026-01-28"
14875
14979
  }
14876
- ]
14980
+ ]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ask
4
4
  module LLM
5
- VERSION = "0.13.7"
5
+ VERSION = "0.14.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-llm-providers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.7
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaka Ruto
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.11.4
18
+ version: 0.12.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 0.11.4
25
+ version: 0.12.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: ask-auth
28
28
  requirement: !ruby/object:Gem::Requirement