fix: implement json_schema fallback for OpenAI-compatible providers (#1343)
When json_schema response_format is sent to models that do not natively
support Structured Output (e.g. DeepSeek/Ollama/local LLMs via
openai-compatible-* providers), they often return empty or malformed
content.
Detect response_format.type === "json_schema", inject the schema into the
system prompt, and downgrade response_format to json_object so Structured
Output works transparently across openai-compatible providers.
Gated to provider.startsWith("openai-compatible-") so providers with
native Structured Output support are not downgraded.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,7 +12,28 @@ export class DefaultExecutor extends BaseExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transformRequest(model, body) {
|
transformRequest(model, body) {
|
||||||
return injectReasoningContent({ provider: this.provider, model, body });
|
const transformed = this.applyJsonSchemaFallback(body);
|
||||||
|
return injectReasoningContent({ provider: this.provider, model, body: transformed });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback json_schema → json_object for openai-compatible providers without native Structured Output.
|
||||||
|
applyJsonSchemaFallback(body) {
|
||||||
|
if (!this.provider?.startsWith?.("openai-compatible-")) return body;
|
||||||
|
const rf = body?.response_format;
|
||||||
|
if (rf?.type !== "json_schema" || !rf.json_schema?.schema) return body;
|
||||||
|
|
||||||
|
const schemaJson = JSON.stringify(rf.json_schema.schema, null, 2);
|
||||||
|
const prompt = `You must respond with valid JSON that strictly follows this JSON schema:\n\`\`\`json\n${schemaJson}\n\`\`\`\nRespond ONLY with the JSON object, no other text.`;
|
||||||
|
|
||||||
|
const messages = Array.isArray(body.messages) ? body.messages.map(m => ({ ...m })) : [];
|
||||||
|
const sys = messages.find(m => m.role === "system");
|
||||||
|
if (sys) {
|
||||||
|
if (typeof sys.content === "string") sys.content = `${sys.content}\n\n${prompt}`;
|
||||||
|
else if (Array.isArray(sys.content)) sys.content.push({ type: "text", text: `\n\n${prompt}` });
|
||||||
|
} else {
|
||||||
|
messages.unshift({ role: "system", content: prompt });
|
||||||
|
}
|
||||||
|
return { ...body, messages, response_format: { type: "json_object" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user