Repository navigation
fix: accept stop as a string, and answer a request that does not decode with 400 - #223
Conversation
…code with 400 OpenAI's `stop` is a string, an array, or null; both request types decoded only the array form, so a bare string failed to decode. StopSequences now takes either form, and null or absent still means no client stops. That decode failure was answered as 500 server_error, which the OpenAI SDKs retry as a transient error. Only a DecodingError from the request-body decode now maps to 400 invalid_request_error with `param` taken from the coding path; everything else on these routes still returns 500. Closes SharpAI#221.
Both SharpAI#220 and this branch added a block before the results footer of tests/test-contract.sh. The seed assertions keep their numbers (9, 9b); the request-shape assertions move to 10 and 10b.
|
The one red job, The uploaded That is a separate bug, written up with the line references in #224. |
|
Thank you for this, and for keeping the branch current so quickly. The decode-to-400 mapping and the A note on what we did to the branch: the last CI run on it ( We will merge once that run is green. |
Closes #221.
What
Two request-handling gaps, both on
/v1/chat/completionsand/v1/completions:stopaccepts a bare string. OpenAI documentsstopas "string / array / null". Both request types decoded only the array, so"stop": "\n"(what several SDKs and llama.cpp-style clients send) failed to decode.StopSequencesnow takes either form; the array form andnullbehave exactly as before.500 server_error / internal_error. It is now400 invalid_request_errorwith the offendingparamnamed (stop,messages,messages.0.role, …), the shape OpenAI uses and clients key on.Only
DecodingErrorfrom the request-body decode is mapped; everything else on these routes still returns 500 as today.Why
Before, on
main:The OpenAI SDKs treat a 400 as final but retry a 5xx (openai-python: two retries by default), so a client sending a string stop paid three round trips to learn nothing, and the error told it the server was at fault.
Verified
RequestValidationTests(new):stopas string / array / null / absent on both request types, a non-string value still rejected, and the 400 payload for a missing key, a type mismatch, a nested path and malformed JSON. The string-stop cases are red onmain.tests/test-contract.shgained two assertions: a barestopstring is accepted and honoured, and"stop": 42answers400 invalid_request_errorwithparam: "stop". Both red onmain.swift test --filter SwiftLMTestsgreen locally (M1 Max, Xcode 27 / Swift 6.4); contract script run againstmlx-community/Qwen3-0.6B-4bit.