From e0db862781378ff27468845afbb44f3df6ebaada Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Sat, 19 Sep 2026 04:31:55 -0700 Subject: [PATCH] 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. --- ...odel_prices_and_context_window_backup.json | 224 ++++++++++++++++++ model_prices_and_context_window.json | 224 ++++++++++++++++++ model_prices_and_context_window.schema.json | 108 +++++++++ .../deepseek/test_deepseek_cost_calculator.py | 70 ++++++ .../test_litellm/test_model_prices_schema.py | 41 ++++ tests/test_litellm/test_utils.py | 32 +++ 6 files changed, 699 insertions(+) create mode 100644 tests/test_litellm/llms/deepseek/test_deepseek_cost_calculator.py diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 32619a86247..4dbf0337894 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -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": [ diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 32619a86247..4dbf0337894 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -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": [ diff --git a/model_prices_and_context_window.schema.json b/model_prices_and_context_window.schema.json index 8d79c560175..44b2569defd 100644 --- a/model_prices_and_context_window.schema.json +++ b/model_prices_and_context_window.schema.json @@ -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 diff --git a/tests/test_litellm/llms/deepseek/test_deepseek_cost_calculator.py b/tests/test_litellm/llms/deepseek/test_deepseek_cost_calculator.py new file mode 100644 index 00000000000..c3a4cdad0ac --- /dev/null +++ b/tests/test_litellm/llms/deepseek/test_deepseek_cost_calculator.py @@ -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 + ) diff --git a/tests/test_litellm/test_model_prices_schema.py b/tests/test_litellm/test_model_prices_schema.py index 918aff806c1..052278631e2 100644 --- a/tests/test_litellm/test_model_prices_schema.py +++ b/tests/test_litellm/test_model_prices_schema.py @@ -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( diff --git a/tests/test_litellm/test_utils.py b/tests/test_litellm/test_utils.py index 8bb9a7e86a3..537c5ed45a4 100644 --- a/tests/test_litellm/test_utils.py +++ b/tests/test_litellm/test_utils.py @@ -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": {