Let the gateway target non-OpenAI upstreams and allow client model passthrough

gateway_thinking_dialect overrides the URL-sniffed protocol dialect for a
reverse-proxied upstream (e.g. Ollama) whose URL carries no identifying
token; upstream_capabilities() uses the same effective dialect to stop
sending stream_options to upstreams that don't support it. gateway_allow_client_model
lets a client-requested model name through even with force-model on, for
an upstream that serves many models with no single stable alias.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XjW4qocnaJxhugUi5ca8Wo
This commit is contained in:
2026-09-07 13:36:42 +02:00
co-authored by Claude Sonnet 5
parent 54f06a957d
commit d9ff99c4a0
7 changed files with 239 additions and 12 deletions
@@ -942,6 +942,107 @@ class FakeClientWithUsage_openai_gateway(FakeClient_openai_gateway):
)
def test_ollama_stream_does_not_send_stream_options(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_upstream_url"] = "http://127.0.0.1:11434/api/chat"
rt = svc.runtime()
run_async(
rt.handle_chat(
{
"messages": [{"role": "user", "content": "hi"}],
"stream": True,
"stream_options": {"include_usage": True},
},
cfg,
("guest", "ollama_stream_opts"),
"test",
"default",
)
)
upstream_payload = rt._client.calls[-1][1]
assert upstream_payload["stream"] is True
assert "stream_options" not in upstream_payload
assert upstream_payload["think"] is False
def test_ollama_explicit_dialect_overrides_url(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_upstream_url"] = "https://ai.example.com/v1/chat/completions"
cfg["gateway_thinking_dialect"] = "ollama"
rt = svc.runtime()
run_async(
rt.handle_chat(
{"messages": [{"role": "user", "content": "hi"}]},
cfg,
("guest", "ollama_dialect_override"),
"test",
"default",
)
)
body = rt._client.calls[-1][1]
assert body["think"] is False
assert "thinking" not in body
def test_client_model_allowed_when_allow_client_model_on(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_force_model"] = True
cfg["gateway_allow_client_model"] = True
cfg["gateway_model"] = "deepseek-chat"
rt = svc.runtime()
run_async(
rt.handle_chat(
{"model": "llama3.2", "messages": [{"role": "user", "content": "hi"}]},
cfg,
("guest", "client_model"),
"test",
"default",
)
)
assert rt._client.calls[-1][1]["model"] == "llama3.2"
def test_molodetz_alias_still_remapped_with_allow_client_model(local_db, monkeypatch):
from devplacepy.services.openai_gateway import routing
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
original = routing.model_store.get("molodetz")
routing.model_store.remove("molodetz")
try:
svc = GatewayService()
cfg = svc.effective_config()
cfg["gateway_force_model"] = True
cfg["gateway_allow_client_model"] = True
cfg["gateway_model"] = "deepseek-chat"
rt = svc.runtime()
run_async(
rt.handle_chat(
{"model": "molodetz", "messages": [{"role": "user", "content": "hi"}]},
cfg,
("guest", "molodetz_alias"),
"test",
"default",
)
)
assert rt._client.calls[-1][1]["model"] == "deepseek-chat"
finally:
if original is not None:
routing.model_store.set(
routing.ModelRouteIn(
**{
field: getattr(original, field)
for field in routing.ModelRouteIn.model_fields
}
)
)
def test_stream_forwarded_to_upstream_with_forced_include_usage(local_db, monkeypatch):
monkeypatch.setattr(gwmod.httpx, "AsyncClient", FakeClient_openai_gateway)
svc = GatewayService()
@@ -4,6 +4,7 @@ from devplacepy.services.openai_gateway.thinking import (
apply_thinking,
client_thinking_enabled,
thinking_dialect,
upstream_capabilities,
)
@@ -15,6 +16,38 @@ def test_dialect_from_upstream_url():
assert thinking_dialect("https://unknown.example/v1/chat/completions") == "deepseek"
def test_upstream_capabilities_openai_full_schema():
caps = upstream_capabilities("https://api.deepseek.com/chat/completions")
assert caps.dialect == "deepseek"
assert caps.supports_stream_options is True
assert caps.supports_stream_usage is True
def test_upstream_capabilities_ollama_lacks_stream_options():
caps = upstream_capabilities("http://127.0.0.1:11434/api/chat")
assert caps.dialect == "ollama"
assert caps.supports_stream_options is False
assert caps.supports_stream_usage is False
def test_upstream_capabilities_explicit_dialect_override():
caps = upstream_capabilities(
"https://ai.example.com/v1/chat/completions", dialect="ollama"
)
assert caps.dialect == "ollama"
assert caps.supports_stream_options is False
def test_apply_thinking_respects_explicit_dialect_override():
without = apply_thinking({}, "https://ai.example.com/v1/chat/completions")
assert without["thinking"] == {"type": "disabled"}
with_override = apply_thinking(
{}, "https://ai.example.com/v1/chat/completions", dialect="ollama"
)
assert with_override["think"] is False
assert "thinking" not in with_override
def test_client_intent_unspecified():
assert client_thinking_enabled({}) is None
assert client_thinking_enabled({"messages": []}) is None