fix(#4536): gate service tier on effective send model, not saved default

This commit is contained in:
Rod Boev
2026-06-20 23:41:31 -04:00
committed by nesquena-hermes
parent 4d64c18832
commit 2f2d36d4eb
4 changed files with 74 additions and 8 deletions
+21 -7
View File
@@ -3544,19 +3544,33 @@ def _public_main_service_tier(model_cfg: dict) -> str:
return "priority" if service_tier == "priority" else ""
def _main_model_request_overrides(config_data: dict) -> dict:
"""Return supported runtime request overrides for the main chat model."""
def _main_model_request_overrides(
config_data: dict,
effective_model: str | None = None,
effective_provider: str | None = None,
) -> dict:
"""Return supported runtime request overrides for the main chat model.
When *effective_model* / *effective_provider* are supplied, the
service-tier gate checks those instead of the saved default model,
so a per-session model switch to a non-OpenAI provider does not
leak ``service_tier`` onto an unsupported request.
"""
if not isinstance(config_data, dict):
return {}
model_cfg = config_data.get("model", {})
if not isinstance(model_cfg, dict):
return {}
overrides = {}
model_id = str(model_cfg.get("default") or model_cfg.get("name") or "").strip()
resolved_provider = str(model_cfg.get("provider") or "").strip().lower()
if not resolved_provider:
_, resolved_provider, _ = resolve_model_provider(model_id)
if _main_model_supports_service_tier(model_id, resolved_provider):
gate_model = effective_model
gate_provider = effective_provider
if not gate_model:
gate_model = str(model_cfg.get("default") or model_cfg.get("name") or "").strip()
if not gate_provider:
gate_provider = str(model_cfg.get("provider") or "").strip().lower()
if not gate_provider:
_, gate_provider, _ = resolve_model_provider(gate_model)
if _main_model_supports_service_tier(gate_model, gate_provider):
service_tier = str(model_cfg.get("service_tier") or "").strip().lower()
if service_tier == "priority":
overrides["service_tier"] = "priority"
+13
View File
@@ -591,6 +591,15 @@ def _run_gateway_chat_streaming(
prefill_messages = []
base_url = _gateway_base_url(cfg)
api_key = _gateway_api_key()
try:
from api.config import _main_model_request_overrides
_gw_overrides = _main_model_request_overrides(
cfg,
effective_model=model,
effective_provider=model_provider,
)
except Exception:
_gw_overrides = {}
# Capability gate: use runs API when gateway advertises approval support.
_use_runs_api = _gateway_use_runs_api_enabled(cfg) and gateway_supports_approval(base_url, api_key)
if _use_runs_api:
@@ -599,6 +608,8 @@ def _run_gateway_chat_streaming(
body_extras["provider"] = model_provider
if reasoning_effort is not None:
body_extras["reasoning_effort"] = reasoning_effort
if _gw_overrides.get("service_tier"):
body_extras["service_tier"] = _gw_overrides["service_tier"]
try:
final_text, usage = _run_gateway_runs_api_streaming(
session_id, msg_text, model, workspace, stream_id,
@@ -661,6 +672,8 @@ def _run_gateway_chat_streaming(
body["provider"] = model_provider
if reasoning_effort is not None:
body["reasoning_effort"] = reasoning_effort
if _gw_overrides.get("service_tier"):
body["service_tier"] = _gw_overrides["service_tier"]
req = urllib.request.Request(
url,
data=json.dumps(body).encode("utf-8"),
+5 -1
View File
@@ -7026,7 +7026,11 @@ def _run_agent_streaming(
_prefill_context = _load_webui_prefill_context(_cfg)
_prefill_messages = _prefill_messages_with_webui_context(_prefill_context, _cfg)
_prefill_messages = _normalize_prefill_messages_before_user_turn(_prefill_messages)
_main_request_overrides = _main_model_request_overrides(_cfg)
_main_request_overrides = _main_model_request_overrides(
_cfg,
effective_model=resolved_model,
effective_provider=resolved_provider,
)
put('context_status', {
'session_id': session_id,
'prefill': _public_prefill_context_status(_prefill_context),
+35
View File
@@ -94,6 +94,41 @@ class TestIssue4536ServiceTier:
assert payload["main"]["service_tier"] == ""
def test_effective_model_gates_service_tier_forwarding(self):
"""service_tier must be gated on the effective send model, not the saved default."""
from api import config
cfg_priority = {"model": {"provider": "openai", "default": "gpt-5.5", "service_tier": "priority"}}
openai_effective = config._main_model_request_overrides(
cfg_priority, effective_model="gpt-5.5", effective_provider="openai",
)
assert openai_effective.get("service_tier") == "priority"
openrouter_effective = config._main_model_request_overrides(
cfg_priority, effective_model="meta-llama/llama-3.1", effective_provider="openrouter",
)
assert openrouter_effective == {}
custom_effective = config._main_model_request_overrides(
cfg_priority, effective_model="my-local-model", effective_provider="custom:local",
)
assert custom_effective == {}
codex_effective = config._main_model_request_overrides(
cfg_priority, effective_model="gpt-5.3-codex", effective_provider="openai-codex",
)
assert codex_effective == {}
def test_no_effective_params_falls_back_to_saved_default(self):
"""Without effective_model/provider, the function still reads the saved config."""
from api import config
result = config._main_model_request_overrides(
{"model": {"provider": "openai", "default": "gpt-5.5", "service_tier": "priority"}},
)
assert result == {"service_tier": "priority"}
def test_switching_main_model_away_from_openai_clears_service_tier(self, monkeypatch, tmp_path):
"""A non-OpenAI default-model save should remove stale OpenAI service-tier state."""
from api import config