This commit is contained in:
2026-07-09 02:52:54 +02:00
parent 818568c609
commit 48bb6c2ec2
95 changed files with 6115 additions and 267 deletions
@@ -331,6 +331,140 @@ def test_embeddings_disabled_returns_503(local_db, monkeypatch):
assert resp.status_code == 503
class FakeImageClient_openai_gateway:
def __init__(self, *a, **k):
self.calls = []
def build_request(self, method, url, headers=None, json=None, content=None):
return FakeRequest(method, url, json)
async def send(self, request):
self.calls.append((request.url, request.json_body))
body = request.json_body or {}
return FakeResp_openai_gateway(
payload={
"created": 1,
"model": body.get("model"),
"data": [{"b64_json": "aGVsbG8="}],
"usage": {"cost": 0.05},
}
)
async def aclose(self):
pass
def test_images_remaps_alias_to_configured_model(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeImageClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_force_model"] = False
cfg["gateway_image_enabled"] = True
cfg["gateway_image_model"] = "black-forest-labs/flux.2-pro"
rt = svc.runtime()
run_async(
rt.handle_images(
{
"model": "molodetz-img-small",
"prompt": "award emblem",
"size": "512x512",
},
cfg,
("guest", "test"),
"test",
)
)
assert rt._client.calls[-1][1]["model"] == "black-forest-labs/flux.2-pro"
def test_image_route_overrides_upstream(local_db, monkeypatch):
from devplacepy.services.openai_gateway import routing
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeImageClient_openai_gateway)
routing.provider_store.set(
routing.ProviderIn(
name="gwimg",
base_url="https://routed.example/v1/chat/completions",
api_key="img-key",
)
)
routing.model_store.set(
routing.ModelRouteIn(
source_model="custom-img",
provider="gwimg",
target_model="vendor/flux-pro",
kind="image",
price_input_per_m=0.06,
)
)
try:
svc = GatewayService()
cfg = svc.effective_config()
rt = svc.runtime()
run_async(
rt.handle_images(
{
"model": "custom-img",
"prompt": "trophy",
"response_format": "b64_json",
},
cfg,
("guest", "test"),
"test",
)
)
url, body = rt._client.calls[-1]
assert str(url) == "https://routed.example/v1/images"
assert body["model"] == "vendor/flux-pro"
finally:
routing.model_store.remove("custom-img")
routing.provider_store.remove("gwimg")
def test_images_success_records_ledger(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeImageClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_image_enabled"] = True
cfg["gateway_image_model"] = "black-forest-labs/flux.2-pro"
rt = svc.runtime()
before = rt.image_calls
resp = run_async(
rt.handle_images(
{"model": "molodetz-img-small", "prompt": "badge"},
cfg,
("guest", "img_ledger"),
"test",
)
)
assert resp.status_code == 200
payload = json.loads(bytes(resp.body).decode())
assert payload["data"][0]["b64_json"] == "aGVsbG8="
assert rt.image_calls == before + 1
row = get_table("gateway_usage_ledger").find_one(owner_id="img_ledger")
assert row is not None
assert row["backend"] == "image"
assert row["endpoint"] == "images/generations"
assert row["requested_model"] == "molodetz-img-small"
assert row["model"] == "black-forest-labs/flux.2-pro"
assert row["success"] == 1
assert float(row["cost_usd"]) == 0.05
def test_images_disabled_returns_503(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeImageClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_image_enabled"] = False
rt = svc.runtime()
resp = run_async(
rt.handle_images(
{"prompt": "badge"}, cfg, ("guest", "test"), "test"
)
)
assert resp.status_code == 503
def test_compute_cost_embed_branch():
from devplacepy.services.openai_gateway.usage import (
Pricing,
@@ -1,5 +1,8 @@
# retoor <retoor@molodetz.nl>
import pytest
from pydantic import ValidationError
from devplacepy.services.openai_gateway import routing as r
from devplacepy.services.openai_gateway.usage import pricing_from_cfg
@@ -14,6 +17,7 @@ def _cleanup(providers, models):
def test_no_routes_pass_through(local_db):
assert r.chat_overlay("ghost-model-xyz", {}) is None
assert r.embed_overlay("ghost-embed-xyz", {}) is None
assert r.image_overlay("ghost-image-xyz", {}) is None
def test_chat_route_overlay_and_economy(local_db):
@@ -80,6 +84,37 @@ def test_vision_merge_overlay(local_db):
_cleanup(["utvis"], ["ut-vision"])
def test_image_route_and_kind_isolation(local_db):
r.provider_store.set(
r.ProviderIn(
name="utimg",
base_url="https://img.example/v1/chat/completions",
api_key="ik",
)
)
r.model_store.set(
r.ModelRouteIn(
source_model="ut-image",
provider="utimg",
target_model="vendor/flux",
kind="image",
price_input_per_m=0.05,
)
)
try:
overlay = r.image_overlay("ut-image", {})
assert overlay["gateway_image_model"] == "vendor/flux"
assert overlay["gateway_image_url"] == "https://img.example/v1/images"
assert overlay["gateway_image_key"] == "ik"
assert overlay["gateway_image_price_per_call"] == 0.05
assert r.chat_overlay("ut-image", {}) is None
assert r.embed_overlay("ut-image", {}) is None
pricing = pricing_from_cfg(overlay)
assert pricing.image_per_call == 0.05
finally:
_cleanup(["utimg"], ["ut-image"])
def test_embed_route_and_kind_isolation(local_db):
r.provider_store.set(
r.ProviderIn(
@@ -140,3 +175,108 @@ def test_blank_provider_uses_default_upstream(local_db):
assert overlay["gateway_price_output_per_m"] == 3.0
finally:
_cleanup([], ["ut-default"])
def test_tier2_and_off_peak_fields_propagate_through_overlay(local_db):
r.model_store.set(
r.ModelRouteIn(
source_model="ut-tiered",
target_model="vendor/tiered",
kind="chat",
price_cache_hit_per_m=0.0028,
price_cache_miss_per_m=0.14,
price_output_per_m=0.28,
context_tier_threshold_tokens=128_000,
price_output_per_m_tier2=0.56,
off_peak_start_minute=990,
off_peak_end_minute=30,
off_peak_discount_pct=25.0,
)
)
try:
overlay = r.chat_overlay("ut-tiered", {})
assert overlay["gateway_context_tier_threshold_tokens"] == 128_000
assert overlay["gateway_price_output_per_m_tier2"] == 0.56
assert overlay["gateway_price_cache_hit_per_m_tier2"] is None
assert overlay["gateway_off_peak_start_minute"] == 990
assert overlay["gateway_off_peak_end_minute"] == 30
assert overlay["gateway_off_peak_discount_pct"] == 25.0
pricing = pricing_from_cfg(overlay)
assert pricing.context_tier_threshold_tokens == 128_000
assert pricing.chat_output_per_m_tier2 == 0.56
assert pricing.chat_cache_hit_per_m_tier2 is None
assert pricing.off_peak_start_minute == 990
finally:
_cleanup([], ["ut-tiered"])
def test_unrouted_request_never_gains_tier_or_off_peak_keys(local_db):
assert r.chat_overlay("ghost-model-untiered", {}) is None
pricing = pricing_from_cfg({})
assert pricing.context_tier_threshold_tokens == 0
assert pricing.off_peak_start_minute is None
assert pricing.off_peak_end_minute is None
assert pricing.chat_output_per_m_tier2 is None
def test_off_peak_window_requires_both_start_and_end():
with pytest.raises(ValidationError):
r.ModelRouteIn(
source_model="ut-bad-window",
target_model="vendor/x",
off_peak_start_minute=60,
)
with pytest.raises(ValidationError):
r.ModelRouteIn(
source_model="ut-bad-window",
target_model="vendor/x",
off_peak_end_minute=120,
)
def test_seed_default_image_routes_is_idempotent(local_db):
r.model_store.remove(r.IMAGE_SOURCE_MODEL)
r.seed_default_image_routes()
route = r.model_store.get(r.IMAGE_SOURCE_MODEL)
assert route is not None
assert route.kind == "image"
assert route.target_model == r.FLUX_TARGET_MODEL
r.seed_default_image_routes()
assert r.model_store.get(r.IMAGE_SOURCE_MODEL).target_model == r.FLUX_TARGET_MODEL
def test_seed_default_deepseek_routes_is_idempotent_and_preserves_customization(
local_db,
):
r.seed_default_deepseek_routes()
flash = r.model_store.get("deepseek-v4-flash")
pro = r.model_store.get("deepseek-v4-pro")
assert flash is not None and pro is not None
assert flash.price_cache_hit_per_m == 0.0028
assert flash.price_cache_miss_per_m == 0.14
assert flash.price_output_per_m == 0.28
assert flash.context_window == 1_048_576
assert pro.price_cache_hit_per_m == 0.003625
assert pro.price_cache_miss_per_m == 0.435
assert pro.price_output_per_m == 0.87
r.model_store.set(
r.ModelRouteIn(
source_model="deepseek-v4-pro",
target_model="deepseek-v4-pro",
price_output_per_m=1.23,
)
)
try:
r.seed_default_deepseek_routes()
assert r.model_store.get("deepseek-v4-pro").price_output_per_m == 1.23
finally:
r.model_store.set(
r.ModelRouteIn(
source_model="deepseek-v4-pro",
target_model="deepseek-v4-pro",
price_cache_hit_per_m=0.003625,
price_cache_miss_per_m=0.435,
price_output_per_m=0.87,
context_window=1_048_576,
)
)
+130
View File
@@ -1,13 +1,28 @@
# retoor <retoor@molodetz.nl>
from dataclasses import replace
from datetime import datetime, timezone
from devplacepy.services.openai_gateway.usage import (
USAGE_FIELDS,
Pricing,
accumulate_usage,
compute_cost,
new_usage_totals,
normalize_usage,
parse_usage_headers,
usage_metric_cards,
)
BASE_PRICING = Pricing(
chat_cache_hit_per_m=0.0028,
chat_cache_miss_per_m=0.14,
chat_output_per_m=0.28,
vision_input_per_m=0.0,
vision_output_per_m=0.0,
embed_input_per_m=0.01,
)
GATEWAY_HEADERS = {
"X-Gateway-Cost-USD": "0.00010000",
"X-Gateway-Model": "molodetz",
@@ -89,3 +104,118 @@ def test_usage_metric_cards_labels_and_formatting():
assert by_label["Total cost"] == "$0.0492"
assert by_label["Avg cost/call"] == "$0.012300"
assert by_label["Avg latency"] == "4200ms"
def test_compute_cost_matches_deepseek_flat_rates_when_no_tier_configured():
norm = normalize_usage(
{
"prompt_tokens": 2000,
"completion_tokens": 100,
"prompt_cache_hit_tokens": 500,
"prompt_cache_miss_tokens": 1500,
}
)
total, input_cost, output_cost, native = compute_cost({}, norm, BASE_PRICING, "chat")
assert native is False
assert abs(input_cost - (500 / 1e6 * 0.0028 + 1500 / 1e6 * 0.14)) < 1e-12
assert abs(output_cost - (100 / 1e6 * 0.28)) < 1e-12
assert abs(total - (input_cost + output_cost)) < 1e-12
def test_compute_cost_switches_to_tier2_above_threshold():
tiered = replace(
BASE_PRICING,
chat_cache_hit_per_m_tier2=0.005,
chat_cache_miss_per_m_tier2=0.25,
chat_output_per_m_tier2=0.5,
context_tier_threshold_tokens=1000,
)
below = normalize_usage({"prompt_tokens": 900, "completion_tokens": 50})
above = normalize_usage({"prompt_tokens": 1001, "completion_tokens": 50})
_, below_input, below_output, _ = compute_cost({}, below, tiered, "chat")
_, above_input, above_output, _ = compute_cost({}, above, tiered, "chat")
assert abs(below_output - (50 / 1e6 * 0.28)) < 1e-12
assert abs(above_output - (50 / 1e6 * 0.5)) < 1e-12
assert below_input != above_input
def test_compute_cost_tier2_leaves_unset_component_at_tier1():
tiered = replace(
BASE_PRICING,
chat_output_per_m_tier2=0.5,
context_tier_threshold_tokens=100,
)
norm = normalize_usage({"prompt_tokens": 200, "completion_tokens": 10})
_, input_cost, output_cost, _ = compute_cost({}, norm, tiered, "chat")
assert abs(output_cost - (10 / 1e6 * 0.5)) < 1e-12
assert abs(input_cost - (200 / 1e6 * 0.14)) < 1e-12
def test_compute_cost_applies_off_peak_discount():
discounted = replace(
BASE_PRICING,
off_peak_start_minute=60,
off_peak_end_minute=120,
off_peak_discount_pct=50.0,
)
norm = normalize_usage({"prompt_tokens": 1000, "completion_tokens": 100})
in_window = datetime(2026, 1, 1, 1, 30, tzinfo=timezone.utc)
outside_window = datetime(2026, 1, 1, 10, 0, tzinfo=timezone.utc)
total_in, _, _, _ = compute_cost({}, norm, discounted, "chat", now=in_window)
total_out, _, _, _ = compute_cost({}, norm, discounted, "chat", now=outside_window)
total_flat, _, _, _ = compute_cost({}, norm, BASE_PRICING, "chat")
assert abs(total_out - total_flat) < 1e-12
assert abs(total_in - total_flat / 2) < 1e-12
def test_compute_cost_off_peak_wraps_past_midnight():
wrapped = replace(
BASE_PRICING,
off_peak_start_minute=23 * 60,
off_peak_end_minute=60,
off_peak_discount_pct=100.0,
)
norm = normalize_usage({"prompt_tokens": 1000, "completion_tokens": 100})
just_after_midnight = datetime(2026, 1, 1, 0, 30, tzinfo=timezone.utc)
midday = datetime(2026, 1, 1, 12, 0, tzinfo=timezone.utc)
total_wrapped, _, _, _ = compute_cost(
{}, norm, wrapped, "chat", now=just_after_midnight
)
total_midday, _, _, _ = compute_cost({}, norm, wrapped, "chat", now=midday)
assert total_wrapped == 0.0
assert total_midday > 0.0
def test_compute_cost_image_branch_flat_per_call():
image_pricing = replace(BASE_PRICING, image_per_call=0.04)
norm = normalize_usage({})
total, input_cost, output_cost, native = compute_cost(
{}, norm, image_pricing, "image"
)
assert native is False
assert output_cost == 0.0
assert abs(total - 0.04) < 1e-9
assert abs(input_cost - 0.04) < 1e-9
def test_compute_cost_image_native_cost_preferred():
from devplacepy.services.openai_gateway.usage import extract_image_usage
image_pricing = replace(BASE_PRICING, image_per_call=0.04)
norm = normalize_usage({})
usage = extract_image_usage({"usage": {"cost": 0.055}})
total, _, _, native = compute_cost(usage, norm, image_pricing, "image")
assert native is True
assert total == 0.055
def test_compute_cost_native_upstream_cost_unaffected_by_tiering():
tiered = replace(
BASE_PRICING,
chat_output_per_m_tier2=100.0,
context_tier_threshold_tokens=1,
)
norm = normalize_usage({"prompt_tokens": 1000, "completion_tokens": 100})
total, _, _, native = compute_cost({"cost": 0.05}, norm, tiered, "chat")
assert native is True
assert total == 0.05