fix(ai-gateway): rewrite JSON Schema oneOf as anyOf when routed to friendli#4002
Open
chrarnoldus wants to merge 6 commits into
Open
fix(ai-gateway): rewrite JSON Schema oneOf as anyOf when routed to friendli#4002chrarnoldus wants to merge 6 commits into
chrarnoldus wants to merge 6 commits into
Conversation
…iendli Friendli does not support the JSON Schema oneOf keyword. For chat completions requests whose provider.order includes friendli, downgrade every oneOf in tool parameters and response_format schemas to anyOf. Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryIncremental diff (one commit since last review) removes an unnecessary Files Reviewed (1 file, incremental)
Previous review findings (unchanged files, carried forward):
Notable non-blocking observations (unchanged):
Reviewed by claude-sonnet-4.6 · 399,263 tokens Review guidance: REVIEW.md from base branch |
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
…logging Refactor the schema rewriting logic to use a dedicated type guard for detecting Friendli chat completions requests. This improves readability and type safety in the provider logic. Additionally, update the `oneOf` to `anyOf` rewriting process to return the count of rewritten schemas and include optional logging to track when these transformations occur in production. - Add `isFriendliChatCompletionsRequest` type guard - Update `rewriteChatCompletionsOneOfAsAnyOf` to support optional logging - Add unit tests for the new type guard and logging behavior Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Remove the try-catch block around the Friendli schema rewrite log to simplify the code, as the logging utility is expected to be safe. Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.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
oneOfkeyword. When a chat completions request is routed through Friendli (provider.ordercontainsfriendli), the upstream provider rejects schemas that useoneOf.apps/web/src/lib/ai-gateway/schema-rewrite.ts:isFriendliChatCompletionsRequest— a type guard that narrows aGatewayRequestto a chat completions request whoseprovider.orderincludesfriendli.rewriteChatCompletionsOneOfAsAnyOf— recursively rewrites everyoneOfkeyword asanyOfacross both tool functionparametersandresponse_format.json_schema.schema, mutating the schemas in place. Cycle-safe via a visited set; merges into any pre-existinganyOfinstead of overwriting it. Logs once per request, but only when at least oneoneOfwas actually rewritten.applyProviderSpecificLogicviaisFriendliChatCompletionsRequest, placed afterapplyPreferredProviderso the effectiveprovider.orderis observed (GLM traffic that prefers Friendli is covered), scoped tochat_completionsrequests only.Verification
oneOfparametersschema whileprovider.orderincludedfriendli, and confirmed the outgoing schema usedanyOfwith nooneOf.friendliinprovider.orderleavesoneOfschemas untouched.Visual Changes
N/A
Reviewer Notes
applyPreferredProvider, so it sees the effectiveprovider.orderregardless of whether Friendli was caller-supplied or preferred by the gateway (e.g. GLM models). It is gated tochat_completions;/responsesand/messagesare unaffected.anyOfandoneOf, theoneOfentries are appended toanyOfrather than overwriting it, to avoid silently dropping schemas.oneOf(XOR) →anyOf(OR) is a deliberate, lossy semantic downgrade: Friendli rejectsoneOf, so the most compatible fallback is to accept any of the sub-schemas.ai_gateway_chat_completions_one_of_rewritten, with model + count) per request, only when something actually changed.