From 21596c82bea800e8e9c6ab4568672ead8453c135 Mon Sep 17 00:00:00 2001
From: Daniel Yudelevich <4537920+yudelevi@users.noreply.github.com>
Date: Fri, 5 Jun 2026 02:08:36 -0700
Subject: [PATCH] feat(moonshot): advertise json_schema response support on
live models (#29683)
litellm.responses() already routes Moonshot through the responses->chat-completions
bridge, and Moonshot honors response_format json_schema on chat completions. The
cost-map entries left supports_response_schema unset, so discovery layers that gate
on that flag dropped Moonshot from structured-output / responses listings even though
the capability works end to end.
Set supports_response_schema on the nine models currently live on api.moonshot.ai:
kimi-k2.5, kimi-k2.6, the moonshot-v1 8k/32k/128k text and vision-preview variants,
and moonshot-v1-auto. Verified against the live API that each honors json_schema and
that litellm.responses() returns schema-valid structured output through the bridge.
---
...odel_prices_and_context_window_backup.json | 9 +++
model_prices_and_context_window.json | 9 +++
.../test_moonshot_chat_transformation.py | 59 +++++++++++--------
3 files changed, 54 insertions(+), 23 deletions(-)
diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json
index 75547fe42d4..25e4c388552 100644
--- a/litellm/model_prices_and_context_window_backup.json
+++ b/litellm/model_prices_and_context_window_backup.json
@@ -25024,6 +25024,7 @@
"source": "https://platform.moonshot.ai/docs/guide/kimi-k2-5-quickstart",
"supports_function_calling": true,
"supports_reasoning": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_video_input": true,
"supports_vision": true
@@ -25040,6 +25041,7 @@
"source": "https://platform.kimi.ai/docs/pricing/chat-k26",
"supports_function_calling": true,
"supports_reasoning": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_video_input": true,
"supports_vision": true
@@ -25152,6 +25154,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-128k-0430": {
@@ -25176,6 +25179,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25189,6 +25193,7 @@
"output_cost_per_token": 3e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-32k-0430": {
@@ -25213,6 +25218,7 @@
"output_cost_per_token": 3e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25226,6 +25232,7 @@
"output_cost_per_token": 2e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-8k-0430": {
@@ -25250,6 +25257,7 @@
"output_cost_per_token": 2e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25263,6 +25271,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"morph/morph-v3-fast": {
diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json
index 1ebc816b261..88627ada1bb 100644
--- a/model_prices_and_context_window.json
+++ b/model_prices_and_context_window.json
@@ -25024,6 +25024,7 @@
"source": "https://platform.moonshot.ai/docs/guide/kimi-k2-5-quickstart",
"supports_function_calling": true,
"supports_reasoning": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_video_input": true,
"supports_vision": true
@@ -25040,6 +25041,7 @@
"source": "https://platform.kimi.ai/docs/pricing/chat-k26",
"supports_function_calling": true,
"supports_reasoning": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_video_input": true,
"supports_vision": true
@@ -25152,6 +25154,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-128k-0430": {
@@ -25176,6 +25179,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25189,6 +25193,7 @@
"output_cost_per_token": 3e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-32k-0430": {
@@ -25213,6 +25218,7 @@
"output_cost_per_token": 3e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25226,6 +25232,7 @@
"output_cost_per_token": 2e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"moonshot/moonshot-v1-8k-0430": {
@@ -25250,6 +25257,7 @@
"output_cost_per_token": 2e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true,
"supports_vision": true
},
@@ -25263,6 +25271,7 @@
"output_cost_per_token": 5e-06,
"source": "https://platform.moonshot.ai/docs/pricing",
"supports_function_calling": true,
+ "supports_response_schema": true,
"supports_tool_choice": true
},
"morph/morph-v3-fast": {
diff --git a/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py b/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py
index b4744a7ed18..1e4d79963c1 100644
--- a/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py
+++ b/tests/test_litellm/llms/moonshot/test_moonshot_chat_transformation.py
@@ -9,15 +9,12 @@ import os
import sys
from unittest.mock import patch
-sys.path.insert(
- 0, os.path.abspath("../../../../..")
-) # Adds the parent directory to the system path
+sys.path.insert(0, os.path.abspath("../../../../..")) # Adds the parent directory to the system path
import pytest
import litellm
import litellm.utils
-from litellm import completion
from litellm.litellm_core_utils.get_model_cost_map import GetModelCostMap
from litellm.llms.moonshot.chat.transformation import MoonshotChatConfig
@@ -232,10 +229,7 @@ class TestMoonshotConfig:
assert result["messages"][0]["role"] == "user"
assert result["messages"][0]["content"] == "What's the weather like?"
assert result["messages"][1]["role"] == "user"
- assert (
- result["messages"][1]["content"]
- == "Please select a tool to handle the current issue."
- )
+ assert result["messages"][1]["content"] == "Please select a tool to handle the current issue."
# Check that tool_choice was removed but tools are preserved
assert "tool_choice" not in result
@@ -273,10 +267,7 @@ class TestMoonshotConfig:
# Check that the message was added
assert len(result["messages"]) == 2
- assert (
- result["messages"][1]["content"]
- == "Please select a tool to handle the current issue."
- )
+ assert result["messages"][1]["content"] == "Please select a tool to handle the current issue."
def test_tool_choice_non_required_preserved(self):
"""Test that non-'required' tool_choice values are preserved"""
@@ -501,9 +492,7 @@ class TestMoonshotConfig:
assert result[0].get("reasoning_content") == "stored thinking"
# The promoted key must be removed from provider_specific_fields to
# avoid sending the value twice in the serialised request body
- assert "reasoning_content" not in (
- result[0].get("provider_specific_fields") or {}
- )
+ assert "reasoning_content" not in (result[0].get("provider_specific_fields") or {})
def test_reasoning_model_fill_called_from_transform_request(self):
"""transform_request injects reasoning_content end-to-end for reasoning models."""
@@ -603,10 +592,7 @@ class TestMoonshotConfig:
result = config.fill_reasoning_content(messages)
# reasoning_content should be preserved, not replaced with placeholder
- assert (
- result[0].get("reasoning_content")
- == "User wants weather"
- )
+ assert result[0].get("reasoning_content") == "User wants weather"
def test_reasoning_content_preserved_in_multi_turn_flow(self):
"""reasoning_content is preserved through multi-turn conversation flow.
@@ -650,10 +636,7 @@ class TestMoonshotConfig:
result = config.fill_reasoning_content(messages)
# reasoning_content should be preserved in the assistant message
- assert (
- result[1].get("reasoning_content")
- == "Planning to call weather tool"
- )
+ assert result[1].get("reasoning_content") == "Planning to call weather tool"
class TestKimiK26ModelRegistry:
@@ -695,3 +678,33 @@ class TestKimiK26ModelRegistry:
"""kimi-k2.6 should be assigned to the moonshot provider."""
model_info = model_cost_map["moonshot/kimi-k2.6"]
assert model_info["litellm_provider"] == "moonshot"
+
+
+class TestMoonshotResponseSchemaSupport:
+ """Every model currently live on api.moonshot.ai supports json_schema
+ response_format, which gates discovery via litellm.responses(). The flag
+ must be true so the capability is advertised honestly."""
+
+ LIVE_MODELS = [
+ "moonshot/kimi-k2.5",
+ "moonshot/kimi-k2.6",
+ "moonshot/moonshot-v1-8k",
+ "moonshot/moonshot-v1-32k",
+ "moonshot/moonshot-v1-128k",
+ "moonshot/moonshot-v1-8k-vision-preview",
+ "moonshot/moonshot-v1-32k-vision-preview",
+ "moonshot/moonshot-v1-128k-vision-preview",
+ "moonshot/moonshot-v1-auto",
+ ]
+
+ @pytest.fixture(autouse=True)
+ def model_cost_map(self):
+ return GetModelCostMap.load_local_model_cost_map()
+
+ @pytest.mark.parametrize("model", LIVE_MODELS)
+ def test_live_model_supports_response_schema(self, model, model_cost_map):
+ assert model_cost_map[model].get("supports_response_schema") is True
+
+ def test_supports_response_schema_utility_reports_true(self, model_cost_map, monkeypatch):
+ monkeypatch.setattr(litellm, "model_cost", model_cost_map)
+ assert litellm.utils.supports_response_schema(model="moonshot/kimi-k2.5") is True