mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
fix(cost): bill DeepSeek V4.1 Flash and V4 Pro at their off-peak rates outside peak hours
DeepSeek charges half the listed rate outside 01:00-04:00 and 06:00-10:00 UTC Monday to Friday, so every deepseek-flash, deepseek-v4-flash, deepseek-v4-flash-vision-exp, and deepseek-v4-pro entry now carries an off_peak_pricing block with those windows and the halved input, output, and cache-hit rates. The generated cost map schema picks up the block, and the regression tests pin the peak and off-peak cost of one call at fixed moments.
This commit is contained in:
parent
1f6e5b60b5
commit
e0db862781
6 changed files with 699 additions and 0 deletions
|
|
@ -59567,6 +59567,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59593,6 +59621,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59619,6 +59675,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59645,6 +59729,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 2.2e-08,
|
||||
"input_cost_per_token": 6.6e-07,
|
||||
"output_cost_per_token": 1.98e-06,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 3.96e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59671,6 +59783,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59697,6 +59837,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59723,6 +59891,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59749,6 +59945,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 2.2e-08,
|
||||
"input_cost_per_token": 6.6e-07,
|
||||
"output_cost_per_token": 1.98e-06,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 3.96e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
|
|||
|
|
@ -59567,6 +59567,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59593,6 +59621,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59619,6 +59675,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59645,6 +59729,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 2.2e-08,
|
||||
"input_cost_per_token": 6.6e-07,
|
||||
"output_cost_per_token": 1.98e-06,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 3.96e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59671,6 +59783,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59697,6 +59837,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59723,6 +59891,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 3e-09,
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"output_cost_per_token": 6e-07,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 1.2e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
@ -59749,6 +59945,34 @@
|
|||
"max_output_tokens": 393216,
|
||||
"max_tokens": 393216,
|
||||
"mode": "chat",
|
||||
"off_peak_pricing": {
|
||||
"cache_read_input_token_cost": 2.2e-08,
|
||||
"input_cost_per_token": 6.6e-07,
|
||||
"output_cost_per_token": 1.98e-06,
|
||||
"windows": [
|
||||
{
|
||||
"hours_utc": [
|
||||
"00:00-01:00",
|
||||
"04:00-06:00",
|
||||
"10:00-00:00"
|
||||
],
|
||||
"weekdays": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"hours_utc": "00:00-00:00",
|
||||
"weekdays": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"output_cost_per_token": 3.96e-06,
|
||||
"source": "https://api-docs.deepseek.com/quick_start/pricing",
|
||||
"supported_endpoints": [
|
||||
|
|
|
|||
|
|
@ -457,6 +457,114 @@
|
|||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"off_peak_pricing": {
|
||||
"type": "object",
|
||||
"description": "Rates that replace the same-named base fields while the request falls inside the stated UTC windows.",
|
||||
"properties": {
|
||||
"hours_utc": {
|
||||
"description": "UTC \"HH:MM-HH:MM\" window, or a list of them; a window may wrap past midnight.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d-([01]\\d|2[0-3]):[0-5]\\d$"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d-([01]\\d|2[0-3]):[0-5]\\d$"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hours_utc": {
|
||||
"description": "UTC \"HH:MM-HH:MM\" window, or a list of them; a window may wrap past midnight.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d-([01]\\d|2[0-3]):[0-5]\\d$"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d-([01]\\d|2[0-3]):[0-5]\\d$"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"weekdays": {
|
||||
"type": "array",
|
||||
"description": "ISO-8601 weekday numbers (1 = Monday .. 7 = Sunday) or English day names the window applies on.",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 7
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "(?i)^(mon|monday|tue|tues|tuesday|wed|wednesday|thu|thur|thurs|thursday|fri|friday|sat|saturday|sun|sunday)$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hours_utc"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"weekday_timezone": {
|
||||
"type": "string",
|
||||
"description": "IANA zone the weekdays of each window are read on; defaults to UTC."
|
||||
},
|
||||
"input_cost_per_token": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"output_cost_per_token": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"output_cost_per_reasoning_token": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"cache_read_input_token_cost": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"cache_creation_input_token_cost": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"hours_utc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"windows"
|
||||
]
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"output_cost_per_audio_token": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
from datetime import datetime, timezone
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
import litellm
|
||||
from litellm._internal_context import pinned_billing_time
|
||||
from litellm.types.utils import ModelResponse, PromptTokensDetailsWrapper, Usage
|
||||
|
||||
PEAK_MOMENTS: Final = (
|
||||
pytest.param(datetime(2026, 9, 22, 8, 0, tzinfo=timezone.utc), id="tuesday-08:00"),
|
||||
pytest.param(datetime(2026, 9, 25, 9, 59, tzinfo=timezone.utc), id="friday-09:59"),
|
||||
pytest.param(datetime(2026, 9, 21, 1, 0, tzinfo=timezone.utc), id="monday-01:00"),
|
||||
)
|
||||
OFF_PEAK_MOMENTS: Final = (
|
||||
pytest.param(datetime(2026, 9, 26, 2, 0, tzinfo=timezone.utc), id="saturday-02:00"),
|
||||
pytest.param(datetime(2026, 9, 27, 8, 0, tzinfo=timezone.utc), id="sunday-08:00"),
|
||||
pytest.param(datetime(2026, 9, 21, 0, 30, tzinfo=timezone.utc), id="monday-00:30"),
|
||||
pytest.param(datetime(2026, 9, 23, 5, 0, tzinfo=timezone.utc), id="wednesday-05:00"),
|
||||
pytest.param(datetime(2026, 9, 24, 10, 0, tzinfo=timezone.utc), id="thursday-10:00"),
|
||||
pytest.param(datetime(2026, 9, 22, 12, 0, tzinfo=timezone.utc), id="tuesday-12:00"),
|
||||
)
|
||||
PEAK_COST_PER_MILLION_IN_AND_OUT_WITH_400K_CACHE_HITS: Final = {
|
||||
"deepseek-flash": 1.3824,
|
||||
"deepseek-v4-pro": 4.7696,
|
||||
}
|
||||
|
||||
|
||||
def one_million_in_and_out_with_400k_cache_hits(model: str) -> ModelResponse:
|
||||
return ModelResponse(
|
||||
model=model,
|
||||
usage=Usage(
|
||||
prompt_tokens=1_000_000,
|
||||
completion_tokens=1_000_000,
|
||||
total_tokens=2_000_000,
|
||||
prompt_tokens_details=PromptTokensDetailsWrapper(cached_tokens=400_000),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def deepseek_cost_at(model: str, moment: datetime) -> float:
|
||||
with pinned_billing_time(moment):
|
||||
return litellm.completion_cost(
|
||||
completion_response=one_million_in_and_out_with_400k_cache_hits(model),
|
||||
model=model,
|
||||
custom_llm_provider="deepseek",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("local_model_cost_map")
|
||||
@pytest.mark.parametrize(("model", "peak_cost"), PEAK_COST_PER_MILLION_IN_AND_OUT_WITH_400K_CACHE_HITS.items())
|
||||
@pytest.mark.parametrize("moment", PEAK_MOMENTS)
|
||||
def test_deepseek_bills_the_listed_rate_during_weekday_peak_hours(model: str, peak_cost: float, moment: datetime):
|
||||
assert deepseek_cost_at(model, moment) == pytest.approx(peak_cost)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("local_model_cost_map")
|
||||
@pytest.mark.parametrize(("model", "peak_cost"), PEAK_COST_PER_MILLION_IN_AND_OUT_WITH_400K_CACHE_HITS.items())
|
||||
@pytest.mark.parametrize("moment", OFF_PEAK_MOMENTS)
|
||||
def test_deepseek_bills_half_the_listed_rate_off_peak(model: str, peak_cost: float, moment: datetime):
|
||||
assert deepseek_cost_at(model, moment) == pytest.approx(peak_cost / 2)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("local_model_cost_map")
|
||||
@pytest.mark.parametrize("alias", ("deepseek-v4-flash", "deepseek-v4-flash-vision-exp", "deepseek/deepseek-flash"))
|
||||
def test_deepseek_flash_aliases_follow_the_same_off_peak_schedule(alias: str):
|
||||
saturday: Final = datetime(2026, 9, 26, 2, 0, tzinfo=timezone.utc)
|
||||
assert deepseek_cost_at(alias, saturday) == pytest.approx(
|
||||
PEAK_COST_PER_MILLION_IN_AND_OUT_WITH_400K_CACHE_HITS["deepseek-flash"] / 2
|
||||
)
|
||||
|
|
@ -367,6 +367,47 @@ def test_active_mistral_chat_rows_price_cache_reads_below_input(path: Path):
|
|||
assert drifted == []
|
||||
|
||||
|
||||
DEEPSEEK_PRICED_ROWS: Final = tuple(
|
||||
f"{prefix}{name}"
|
||||
for name in ("deepseek-flash", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp", "deepseek-v4-pro")
|
||||
for prefix in ("", "deepseek/")
|
||||
)
|
||||
DEEPSEEK_OFF_PEAK_WINDOWS: Final = (
|
||||
{"hours_utc": ["00:00-01:00", "04:00-06:00", "10:00-00:00"], "weekdays": [1, 2, 3, 4, 5]},
|
||||
{"hours_utc": "00:00-00:00", "weekdays": [6, 7]},
|
||||
)
|
||||
DEEPSEEK_HALVED_RATES: Final = ("input_cost_per_token", "output_cost_per_token", "cache_read_input_token_cost")
|
||||
|
||||
|
||||
def deepseek_off_peak_drift(entry: Mapping[str, object]) -> str | None:
|
||||
block: Final = entry.get("off_peak_pricing")
|
||||
if not isinstance(block, dict):
|
||||
return "no off_peak_pricing block"
|
||||
if tuple(block.get("windows", ())) != DEEPSEEK_OFF_PEAK_WINDOWS:
|
||||
return f"windows={block.get('windows')}"
|
||||
halved: Final = {rate: block.get(rate) for rate in DEEPSEEK_HALVED_RATES}
|
||||
expected: Final = {rate: float(str(entry[rate])) / 2 for rate in DEEPSEEK_HALVED_RATES}
|
||||
mismatched: Final = {
|
||||
rate for rate in DEEPSEEK_HALVED_RATES if halved[rate] != pytest.approx(expected[rate], rel=1e-9)
|
||||
}
|
||||
return f"off-peak rates {halved} are not half of the listed rates" if mismatched else None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", (PRICES_PATH, BACKUP_PRICES_PATH), ids=("main", "backup"))
|
||||
def test_deepseek_rows_bill_half_rate_outside_weekday_peak_hours(path: Path):
|
||||
"""DeepSeek charges half its listed rate outside 01:00-04:00 and 06:00-10:00 UTC Monday to
|
||||
Friday (api-docs.deepseek.com/quick_start/pricing, read 2026-09-19), so every row on that
|
||||
pricing page carries an off_peak_pricing block with those windows and the halved rates."""
|
||||
rows: Mapping[str, object] = json.loads(path.read_text())
|
||||
drifted: Final = {
|
||||
name: deepseek_off_peak_drift(entry)
|
||||
for name in DEEPSEEK_PRICED_ROWS
|
||||
if isinstance(entry := rows.get(name), dict) and deepseek_off_peak_drift(entry) is not None
|
||||
}
|
||||
assert drifted == {}
|
||||
assert all(name in rows for name in DEEPSEEK_PRICED_ROWS)
|
||||
|
||||
|
||||
PROVIDER_LABELS_WITHOUT_A_MODEL_SET: Final = frozenset({"sagemaker", "bedrock_converse"})
|
||||
MODES_SERVED_OUTSIDE_THE_LLM_PROVIDER_REGISTRY: Final = frozenset({"search", "evaluation"})
|
||||
VERTEX_FAMILIES_A_VERTEX_WILDCARD_GRANT_DOES_NOT_LIST: Final = frozenset(
|
||||
|
|
|
|||
|
|
@ -952,6 +952,38 @@ def test_aaamodel_prices_and_context_window_json_is_valid():
|
|||
"supports_image_size": {"type": "boolean"},
|
||||
"supports_native_structured_output": {"type": "boolean"},
|
||||
"use_openai_responses_path": {"type": "boolean"},
|
||||
"off_peak_pricing": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hours_utc": {
|
||||
"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}],
|
||||
},
|
||||
"windows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hours_utc": {
|
||||
"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}],
|
||||
},
|
||||
"weekdays": {
|
||||
"type": "array",
|
||||
"items": {"oneOf": [{"type": "integer"}, {"type": "string"}]},
|
||||
},
|
||||
},
|
||||
"required": ["hours_utc"],
|
||||
"additionalProperties": False,
|
||||
},
|
||||
},
|
||||
"weekday_timezone": {"type": "string"},
|
||||
"input_cost_per_token": {"type": "number"},
|
||||
"output_cost_per_token": {"type": "number"},
|
||||
"output_cost_per_reasoning_token": {"type": "number"},
|
||||
"cache_read_input_token_cost": {"type": "number"},
|
||||
"cache_creation_input_token_cost": {"type": "number"},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
},
|
||||
"tiered_pricing": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue