Upstream source
Problem
JSON Schema requires required to be an array of property names. Some clients emit "required": null in function/tool schemas. Strict upstreams reject the whole request; upstream #7531 reports this with xAI, Moonshot and Xiaomi MiMo.
The intended compatibility repair is to drop a null required member (not replace it with []), including nested schema nodes, while preserving valid required arrays.
api.lmm.best gap
Current main does not yet have upstream's unified relayconvert/internal/toolconv.ExtractRequest funnel, so #7531 cannot be safely cherry-picked.
Relevant current shapes are split by protocol:
- OpenAI Chat:
dto.GeneralOpenAIRequest.Tools []ToolCallRequest; FunctionRequest.Parameters is any.
- Claude Messages:
dto.ClaudeRequest.Tools is any; tool input_schema can retain required: null.
- OpenAI Responses: tool payload is retained as raw/dynamic JSON in the request DTO/conversion path.
- Gemini has its own function-declaration conversion path.
A one-protocol patch would leave equivalent failures in the other routes. Sanitizing arbitrary request JSON globally would also be too broad and could mutate non-tool payloads or explicit pass-through behavior.
Recommended LMM-native implementation
Add one protocol-neutral tool-schema sanitizer at the relay conversion/request-normalization boundary that is invoked for decoded OpenAI Chat, OpenAI Responses, Claude Messages and Gemini requests before an upstream-compatible request is emitted.
Rules:
- Only sanitize function/tool JSON Schema payloads (
parameters, input_schema, Gemini function declaration parameters, Responses function parameters), not arbitrary request objects.
- Recursively remove a key only when the key is exactly
required and its value is JSON null.
- Preserve valid arrays, empty arrays, strings/numbers/booleans,
properties, items, $defs/definitions, combinators and unknown schema keywords unchanged.
- Bound recursion/depth (upstream uses 64) so malformed/hostile schemas cannot cause unbounded stack growth.
- Do not invent
required: []; absence is the compatibility representation.
- Preserve explicit raw pass-through semantics: if the channel/request is configured for byte-for-byte pass-through, do not silently rewrite its body unless we make that behavior an explicit compatibility option.
- Keep pricing, groups, model price lock,
/fast, OAuth restrictions, provider selection and admin AI assistant behavior untouched.
Acceptance criteria
- Claude
/v1/messages tool with top-level input_schema.required: null is forwarded without required and no longer fails strict OpenAI-compatible upstreams.
- OpenAI Chat function tool with
function.parameters.required: null is sanitized.
- OpenAI Responses function tool with
parameters.required: null is sanitized.
- Gemini function declaration with
parameters.required: null is sanitized when converted/forwarded.
- Nested null
required values under objects/arrays/combinators are removed.
- A valid
required: ["path"] and required: [] remain byte-equivalent semantically.
- Non-tool JSON containing a field named
required: null is not rewritten.
- Tests cover recursion depth and malformed/non-schema values.
- Existing relaykit conversion tests and Go CI pass.
Why issue first instead of direct port
Upstream #7531 is newly opened and its CI workflow currently requires action rather than being fully green. More importantly, LMM's current relaykit predates the upstream unified toolconv extraction layer, so a direct port would either miss routes or broaden rewriting too far. This should be implemented against LMM's current normalization boundary as one small cross-protocol compatibility patch rather than copied mechanically.
Upstream source
14ce52319f90281437b0a259858afbe4c752b775relaykit/relayconvert/internal/toolconv/decode.gorelaykit/relayconvert/internal/toolconv/schema_sanitize.gorelaykit/relayconvert/internal/toolconv/schema_sanitize_test.goProblem
JSON Schema requires
requiredto be an array of property names. Some clients emit"required": nullin function/tool schemas. Strict upstreams reject the whole request; upstream #7531 reports this with xAI, Moonshot and Xiaomi MiMo.The intended compatibility repair is to drop a null
requiredmember (not replace it with[]), including nested schema nodes, while preserving validrequiredarrays.api.lmm.best gap
Current
maindoes not yet have upstream's unifiedrelayconvert/internal/toolconv.ExtractRequestfunnel, so #7531 cannot be safely cherry-picked.Relevant current shapes are split by protocol:
dto.GeneralOpenAIRequest.Tools []ToolCallRequest;FunctionRequest.Parametersisany.dto.ClaudeRequest.Toolsisany; toolinput_schemacan retainrequired: null.A one-protocol patch would leave equivalent failures in the other routes. Sanitizing arbitrary request JSON globally would also be too broad and could mutate non-tool payloads or explicit pass-through behavior.
Recommended LMM-native implementation
Add one protocol-neutral tool-schema sanitizer at the relay conversion/request-normalization boundary that is invoked for decoded OpenAI Chat, OpenAI Responses, Claude Messages and Gemini requests before an upstream-compatible request is emitted.
Rules:
parameters,input_schema, Gemini function declaration parameters, Responses function parameters), not arbitrary request objects.requiredand its value is JSON null.properties,items,$defs/definitions, combinators and unknown schema keywords unchanged.required: []; absence is the compatibility representation./fast, OAuth restrictions, provider selection and admin AI assistant behavior untouched.Acceptance criteria
/v1/messagestool with top-levelinput_schema.required: nullis forwarded withoutrequiredand no longer fails strict OpenAI-compatible upstreams.function.parameters.required: nullis sanitized.parameters.required: nullis sanitized.parameters.required: nullis sanitized when converted/forwarded.requiredvalues under objects/arrays/combinators are removed.required: ["path"]andrequired: []remain byte-equivalent semantically.required: nullis not rewritten.Why issue first instead of direct port
Upstream #7531 is newly opened and its CI workflow currently requires action rather than being fully green. More importantly, LMM's current relaykit predates the upstream unified
toolconvextraction layer, so a direct port would either miss routes or broaden rewriting too far. This should be implemented against LMM's current normalization boundary as one small cross-protocol compatibility patch rather than copied mechanically.