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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user