fix(openai): harden request building for strict OpenAI-compatible backends#3574
Merged
Conversation
added 2 commits
June 8, 2026 03:29
An empty tool schema (common for no-argument MCP tools) is an empty
json.RawMessage, which makes json.Marshal of the whole chat request fail
with "unexpected end of JSON input" — bricking the entire provider for
every request with a cryptic error. Canonicalize empty to {"type":"object"}.
Strict OpenAI-compatible backends can reject an assistant tool_calls turn whose content is the empty string. null is the OpenAI-spec form and is accepted by DeepSeek (verified against a live multi-tool session), so emit null for that one case and keep the string form (empty included) for every other role. Refs #3526.
dorokuma
pushed a commit
to dorokuma/DeepSeek-Reasonix
that referenced
this pull request
Jun 10, 2026
…kends (esengine#3574) * fix(provider): emit a valid schema for no-param tools An empty tool schema (common for no-argument MCP tools) is an empty json.RawMessage, which makes json.Marshal of the whole chat request fail with "unexpected end of JSON input" — bricking the entire provider for every request with a cryptic error. Canonicalize empty to {"type":"object"}. * fix(openai): send null content for pure tool-call assistant turns Strict OpenAI-compatible backends can reject an assistant tool_calls turn whose content is the empty string. null is the OpenAI-spec form and is accepted by DeepSeek (verified against a live multi-tool session), so emit null for that one case and keep the string form (empty included) for every other role. Refs esengine#3526. --------- Co-authored-by: reasonix <reasonix@deepseek.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two robustness/compat fixes for OpenAI-compatible providers, surfaced while investigating #3526 (switching to a strict OpenAI-compatible backend mid-session →
HTTP 400 "Expecting ',' delimiter").1.
fix(provider): valid schema for no-param toolsA tool with no parameters (common for MCP tools) produces an empty schema. An empty
json.RawMessagemakesjson.Marshalof the whole chat request fail withunexpected end of JSON input— so a single no-arg tool bricks the entire provider for every request, with a cryptic error.CanonicalizeSchemanow maps empty →{"type":"object"}.2.
fix(openai): null content for pure tool-call assistant turnsA pure-
tool_callsassistant turn previously serialized"content":"". Strict OpenAI-compatible backends can reject that.nullis the OpenAI-spec form for a tool-call turn; we now emitnullfor that one case and keep the string form (empty included) for every other role/message.On #3526 specifically
I verified our request serialization is not the cause: a mid-session request (assistant
tool_calls+toolresults) marshals to valid JSON (json.Valid == true), and Go'sjson.Marshaleither produces valid JSON or errors — it never emits malformed JSON. So theExpecting ',' delimiter400 is the Agnes/Sapiens server rejecting valid JSON.Change #2 is a spec-aligned compatibility attempt for that server (the
content:""→nullshape is the most likely thing a strict clone trips on). It is verified non-regressive on DeepSeek (a live multi-tool session, whose history carries the tool-call turns ascontent:null, completed with no 400). I could not test it against Agnes/Sapiens directly — @reporter, please try a build with this change and confirm.Testing
go test ./internal/provider/...greencontent:null, no 400)Refs #3526