fix(catalog): used Moonshot MFJS schema for Kimi models on all hosts

- Enable `moonshot-mfjs` tool schema flavor for Kimi-family ids on any host, not just native endpoints, since proxies forward schemas verbatim to Moonshot's validator.
This commit is contained in:
can1357
2026-07-18 06:27:36 +02:00
parent e44ecdc699
commit f60c7791c1
4 changed files with 27 additions and 5 deletions
+10 -1
View File
@@ -38,6 +38,7 @@ import {
adaptSchemaForStrict,
findStrictToolSchemaViolation,
NO_STRICT,
normalizeSchemaForMoonshot,
sanitizeSchemaForOpenAIResponses,
toolWireSchema,
} from "../utils/schema";
@@ -999,7 +1000,15 @@ export function convertTools(
}
const strict = !NO_STRICT && strictMode && tool.strict !== false;
const baseParameters = toolWireSchema(tool);
const responseParameters = sanitizeSchemaForOpenAIResponses(baseParameters);
// MFJS must run AFTER the Responses sanitizer: the sanitizer normalizes
// `{}` → `true` (issue #1179), and Moonshot's validator rejects boolean
// subschemas ("property schema … must be an object"), so the Moonshot
// pass re-coerces them last.
const sanitized = sanitizeSchemaForOpenAIResponses(baseParameters);
const responseParameters =
model.compat.toolSchemaFlavor === "moonshot-mfjs"
? (normalizeSchemaForMoonshot(sanitized) as Record<string, unknown>)
: sanitized;
const { schema: parameters, strict: effectiveStrict } = adaptSchemaForStrict(responseParameters, strict);
// Quarantine a tool whose emitted schema carries a provider-rejecting
// enum/const-vs-type contradiction: dropping just that tool keeps the rest
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Changed
- Kimi-family models now use MFJS tool schema on all hosts, including proxies like OpenRouter that forward schemas to Moonshot
## [17.0.3] - 2026-07-17
### Fixed
+7 -1
View File
@@ -532,7 +532,10 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv
supportsStrictMode: detectStrictModeSupport(provider, baseUrl),
extraBody: isDirectDeepseekReasoning ? { thinking: { type: "enabled" } } : undefined,
toolStrictMode: isCerebras ? "all_strict" : "mixed",
toolSchemaFlavor: isMoonshotNative ? "moonshot-mfjs" : undefined,
// Kimi-family ids trigger MFJS on any host, not just native base URLs:
// proxies (OpenRouter, custom gateways) forward `tools.function.parameters`
// to Moonshot verbatim, which 400s on non-MFJS constructs.
toolSchemaFlavor: isMoonshotNative || isKimiModel ? "moonshot-mfjs" : undefined,
streamIdleTimeoutMs,
stripDeepseekSpecialTokens:
isDeepseekModelIdOrName(spec.id) && (provider === "nvidia" || provider === "deepseek"),
@@ -658,6 +661,9 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
openRouterRouting: undefined,
isOpenRouterHost: isOpenRouter,
wireModelIdMode: isOpenRouter ? "openrouter" : "raw",
// Mirrors buildOpenAICompat: Kimi behind a Responses-capable proxy still
// lands on Moonshot's MFJS validator.
toolSchemaFlavor: isKimiModel ? "moonshot-mfjs" : undefined,
alwaysSendMaxTokens: spec.id ? isKimiModelId(spec.id) : false,
enableGeminiThinkingLoopGuard: modelFamilyToken(spec.id ?? "") === "gemini",
supportsObfuscationOptOut: isOpenAIUrl || spec.provider === "openai",
+6 -3
View File
@@ -314,8 +314,10 @@ export interface OpenAICompat {
* normalization (collapse `const`→`enum`, infer `type` on bare enums, strip
* unsupported validators/`prefixItems`) because Moonshot/Kimi native hosts
* reject standard JSON Schema constructs with HTTP 400. Default:
* auto-detected (`"moonshot-mfjs"` on api.moonshot.ai / api.kimi.com). Set
* `"none"` to opt a custom Moonshot-compatible host out.
* auto-detected — Moonshot native hosts (api.moonshot.ai / api.kimi.com)
* and Kimi-family model ids on any host, since proxies (OpenRouter, custom
* gateways) forward schemas to Moonshot verbatim. Set `"none"` to opt a
* host out.
*/
toolSchemaFlavor?: "moonshot-mfjs" | "none";
/**
@@ -514,6 +516,8 @@ export interface ResolvedOpenAISharedCompat {
openRouterRouting?: OpenAICompat["openRouterRouting"];
/** Provider-specific wire model-id transform applied to the base id. */
wireModelIdMode: "raw" | "firepass" | "fireworks" | "openrouter";
/** See {@link OpenAICompat.toolSchemaFlavor}. Read by both wire paths when converting tools. */
toolSchemaFlavor?: OpenAICompat["toolSchemaFlavor"];
}
/**
@@ -584,7 +588,6 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
thinkingKeep?: OpenAICompat["thinkingKeep"];
streamIdleTimeoutMs?: number;
toolStrictMode: ResolvedToolStrictMode;
toolSchemaFlavor?: OpenAICompat["toolSchemaFlavor"];
/** The model sits behind Vercel AI Gateway. */
isVercelGatewayHost: boolean;
dropThinkingWhenReasoningEffort: boolean;