fix(ai): use adaptive thinking for Kimi Coding

This commit is contained in:
Armin Ronacher
2026-07-16 20:59:54 +02:00
parent aba324504c
commit b8575f60fa
6 changed files with 51 additions and 5 deletions
@@ -7,6 +7,11 @@ const EXPECTED_CURRENT_ADAPTIVE_THINKING_MODELS = [
"anthropic/claude-opus-4-8",
"anthropic/claude-sonnet-5",
"cloudflare-ai-gateway/claude-fable-5",
"kimi-coding/k2p7",
"kimi-coding/k3",
"kimi-coding/kimi-for-coding",
"kimi-coding/kimi-for-coding-highspeed",
"kimi-coding/kimi-k2-thinking",
"opencode/claude-opus-4-8",
"vercel-ai-gateway/anthropic/claude-opus-4.8",
"vercel-ai-gateway/anthropic/claude-sonnet-5",
@@ -27,7 +32,7 @@ describe("Anthropic adaptive thinking model metadata", () => {
expect(flaggedModels).toEqual(expect.arrayContaining([...EXPECTED_CURRENT_ADAPTIVE_THINKING_MODELS].sort()));
expect(flaggedModels).toEqual(
flaggedModels.filter((modelId) =>
/(opus[-.]4[-.][678]|sonnet[-.]4[-.]6|sonnet[-.]5|fable[-.]5)/.test(modelId),
/(opus[-.]4[-.][678]|sonnet[-.]4[-.]6|sonnet[-.]5|fable[-.]5|kimi-coding\/)/.test(modelId),
),
);
});
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { streamSimple } from "../src/compat.ts";
import { getModel, streamSimple } from "../src/compat.ts";
import type { AssistantMessage, Context, Model } from "../src/types.ts";
interface AnthropicPayload {
@@ -32,13 +32,18 @@ function makeModel(allowEmptySignature?: boolean): Model<"anthropic-messages"> {
};
}
function makeContext(thinkingSignature: string, thinking = "internal reasoning"): Context {
function makeContext(
thinkingSignature: string,
thinking = "internal reasoning",
provider = "xiaomi-token-plan-ams",
model = "mimo-v2.5-pro",
): Context {
const assistant: AssistantMessage = {
role: "assistant",
content: [{ type: "thinking", thinking, thinkingSignature }],
provider: "xiaomi-token-plan-ams",
provider,
api: "anthropic-messages",
model: "mimo-v2.5-pro",
model,
timestamp: Date.now(),
usage: {
input: 0,
@@ -91,4 +96,13 @@ describe("Anthropic empty thinking signature compat", () => {
const assistant = payload.messages?.find((message) => message.role === "assistant");
expect(assistant?.content).toEqual([{ type: "thinking", thinking: "internal reasoning", signature: "" }]);
});
it.each(["k3", "kimi-for-coding"] as const)("allows empty signatures for Kimi Coding %s", async (modelId) => {
const model = getModel("kimi-coding", modelId);
expect(model.compat?.allowEmptySignature).toBe(true);
const payload = await capturePayload(model, makeContext(" ", "internal reasoning", "kimi-coding", modelId));
const assistant = payload.messages?.find((message) => message.role === "assistant");
expect(assistant?.content).toEqual([{ type: "thinking", thinking: "internal reasoning", signature: "" }]);
});
});
@@ -89,6 +89,22 @@ describe("Anthropic forceAdaptiveThinking compat override", () => {
expect(payload.output_config).toEqual({ effort: "xhigh" });
});
it.each([
["k2p7", "medium", "medium"],
["k3", "max", "max"],
["kimi-for-coding", "medium", "medium"],
["kimi-for-coding-highspeed", "medium", "medium"],
["kimi-k2-thinking", "medium", "medium"],
] as const)(
"uses adaptive thinking effort without a token budget for Kimi Coding %s",
async (modelId, reasoning, effort) => {
const payload = await capturePayload(getModel("kimi-coding", modelId), { reasoning });
expect(payload.thinking).toEqual({ type: "adaptive", display: "summarized" });
expect(payload.output_config).toEqual({ effort });
},
);
it("allows built-in adaptive models to opt out with compat.forceAdaptiveThinking false", async () => {
const model: Model<"anthropic-messages"> = {
...getModel("anthropic", "claude-opus-4-8"),