From d7a09d975b6324922e93b50074e0fe20f4bd4944 Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Sun, 24 May 2026 16:14:12 +0000 Subject: [PATCH] Drop seed and parallel_tool_calls for Kimi too (PR #5711) Kimi K2.5/K2.6 chat schema documents temperature, top_p and a small fixed set of knobs; seed and parallel_tool_calls are not in it. The frontend already hides those controls (provider-capabilities.ts), so the only way they reach Kimi is a stale client or a direct API caller. Add them to body_omit so the registry strips them on the wire instead of relying on the upstream to 400. Sync the Kimi web-search bypass test to assert both fields are dropped alongside frequency_penalty/temperature/top_p. --- studio/backend/core/inference/providers.py | 18 +++++++++++++----- .../tests/test_sampling_params_routing.py | 8 ++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/studio/backend/core/inference/providers.py b/studio/backend/core/inference/providers.py index b967123ada..0f5620add7 100644 --- a/studio/backend/core/inference/providers.py +++ b/studio/backend/core/inference/providers.py @@ -158,11 +158,19 @@ PROVIDER_REGISTRY: dict[str, dict[str, Any]] = { "notes": "Moonshot API key. China: use base URL https://api.moonshot.cn/v1", "model_id_allowlist": re.compile(r"^kimi-k2\.[56]$"), # Both k2.6 and k2.5 are reasoning-class. The API rejects - # custom sampling: "invalid temperature: only 1 is allowed for - # this model" (and the same shape for top_p). frequency_penalty - # is reported by reviewers to follow the same lock; strip it - # too so non-default values from stale clients do not 400. - "body_omit": ("temperature", "top_p", "frequency_penalty"), + # custom sampling ("invalid temperature: only 1 is allowed for + # this model", same for top_p). frequency_penalty follows the + # same lock on those models. seed and parallel_tool_calls are + # not in Kimi's documented chat schema; strip them too so a + # stale client or direct API caller cannot smuggle them onto + # the wire and 400 the request. + "body_omit": ( + "temperature", + "top_p", + "frequency_penalty", + "seed", + "parallel_tool_calls", + ), # Kimi accepts at most 5 stop strings (each <= 32 bytes) per # https://platform.kimi.ai/docs/api/chat "stop_max": 5, diff --git a/studio/backend/tests/test_sampling_params_routing.py b/studio/backend/tests/test_sampling_params_routing.py index 90509ead5d..889fe2621e 100644 --- a/studio/backend/tests/test_sampling_params_routing.py +++ b/studio/backend/tests/test_sampling_params_routing.py @@ -573,14 +573,14 @@ def test_kimi_web_search_bypass_forwards_new_sampling_fields(monkeypatch): _drive(run()) body = captured["body"] - # Per-provider drops: Kimi locks frequency_penalty/temperature/top_p. + # Kimi locks these: stripped by body_omit in providers.py. assert "frequency_penalty" not in body, body assert "temperature" not in body, body assert "top_p" not in body, body - # Other knobs forward through the bypass. - assert body.get("seed") == 7, body + assert "seed" not in body, body + assert "parallel_tool_calls" not in body, body + # Knobs not on Kimi's drop-list forward through the bypass. assert body.get("stop") == ["END"], body - assert body.get("parallel_tool_calls") is False, body assert body.get("presence_penalty") == 0.5, body