forked from retoor/devplacepy
feat: add provider and model routing tables, admin UI, and audit category for gateway
Implement the multi-provider routing system for the OpenAI gateway, including two new database tables (`gateway_providers`, `gateway_models`) ensured at init, a new admin page at `/admin/gateway` with full CRUD for providers and model routes, and a `"gateway"` audit category mapped to `"ai"`. The routing layer sits transparently on top of the existing single-provider default path: unmatched model names fall through unchanged, while matched routes forward to the configured provider with their own pricing economy, vision model, and context window. Cross-worker cache invalidation uses a shared `_ROUTING_CACHE` bumped via `"gateway_routing"` cache version.
This commit is contained in:
@@ -112,6 +112,47 @@ def test_model_is_forced(local_db, monkeypatch):
|
||||
assert rt._client.calls[-1][1]["model"] == "deepseek-chat"
|
||||
|
||||
|
||||
def test_model_route_overrides_upstream(local_db, monkeypatch):
|
||||
from devplacepy.services.openai_gateway import routing
|
||||
|
||||
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
|
||||
routing.provider_store.set(
|
||||
routing.ProviderIn(
|
||||
name="gwroute",
|
||||
base_url="https://routed.example/v1/chat/completions",
|
||||
api_key="routed-key",
|
||||
)
|
||||
)
|
||||
routing.model_store.set(
|
||||
routing.ModelRouteIn(
|
||||
source_model="custom-pro",
|
||||
provider="gwroute",
|
||||
target_model="vendor/pro",
|
||||
kind="chat",
|
||||
price_output_per_m=9.0,
|
||||
)
|
||||
)
|
||||
try:
|
||||
svc = GatewayService()
|
||||
cfg = svc.effective_config()
|
||||
cfg["gateway_vision_enabled"] = False
|
||||
rt = svc.runtime()
|
||||
run_async(
|
||||
rt.handle_chat(
|
||||
{"model": "custom-pro", "messages": [{"role": "user", "content": "hi"}]},
|
||||
cfg,
|
||||
("guest", "test"),
|
||||
"test",
|
||||
)
|
||||
)
|
||||
url, body = rt._client.calls[-1]
|
||||
assert str(url) == "https://routed.example/v1/chat/completions"
|
||||
assert body["model"] == "vendor/pro"
|
||||
finally:
|
||||
routing.model_store.remove("custom-pro")
|
||||
routing.provider_store.remove("gwroute")
|
||||
|
||||
|
||||
def test_vision_rewrites_image_to_text(local_db, monkeypatch):
|
||||
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
|
||||
svc = GatewayService()
|
||||
|
||||
Reference in New Issue
Block a user