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.
This commit is contained in:
Daniel Han 2026-05-24 16:14:12 +00:00
commit d7a09d975b
2 changed files with 17 additions and 9 deletions

View file

@ -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,

View file

@ -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