@@ -244,6 +244,10 @@ describe("Model Validation Functions", () => {
244244 [ "not json" , "settings:validation.openAiExtraBody.invalidJson" ] ,
245245 [ "[]" , "settings:validation.openAiExtraBody.objectRequired" ] ,
246246 [ JSON . stringify ( { model : "override" } ) , "settings:validation.openAiExtraBody.reservedKeys keys=model" ] ,
247+ [
248+ JSON . stringify ( { response_format : { type : "json_object" } } ) ,
249+ "settings:validation.openAiExtraBody.reservedKeys keys=response_format" ,
250+ ] ,
247251 ] ) ( "rejects invalid OpenAI-compatible Extra Body input" , ( openAiExtraBody , expectedError ) => {
248252 const config : ProviderSettings = {
249253 apiProvider : providerIdentifiers . openai ,
@@ -259,6 +263,58 @@ describe("Model Validation Functions", () => {
259263 } )
260264 } )
261265
266+ describe ( "validateApiConfiguration OpenAI-compatible Extra Body validation" , ( ) => {
267+ const createConfig = ( openAiExtraBody : string ) : ProviderSettings => ( {
268+ apiProvider : providerIdentifiers . openai ,
269+ openAiBaseUrl : "https://api.sailresearch.com/v1" ,
270+ openAiApiKey : "valid-key" ,
271+ openAiModelId : "zai-org/GLM-5.2-FP8" ,
272+ openAiExtraBody,
273+ } )
274+
275+ it ( "accepts a valid Extra Body object through both validation entry points" , ( ) => {
276+ const config = createConfig ( JSON . stringify ( { metadata : { completion_window : "balanced" } } ) )
277+
278+ expect ( validateApiConfiguration ( config , mockRouterModels , allowAllOrganization ) ) . toBeUndefined ( )
279+ expect (
280+ validateApiConfigurationExcludingModelErrors ( config , mockRouterModels , allowAllOrganization ) ,
281+ ) . toBeUndefined ( )
282+ } )
283+
284+ it . each ( [
285+ [ "invalid JSON" , "not json" , "settings:validation.openAiExtraBody.invalidJson" ] ,
286+ [ "non-object JSON" , "[]" , "settings:validation.openAiExtraBody.objectRequired" ] ,
287+ [
288+ "a reserved request API key" ,
289+ JSON . stringify ( { model : "override" } ) ,
290+ "settings:validation.openAiExtraBody.reservedKeys keys=model" ,
291+ ] ,
292+ [
293+ "a reserved security key" ,
294+ '{"constructor":{"prototype":{"polluted":true}}}' ,
295+ "settings:validation.openAiExtraBody.reservedKeys keys=constructor" ,
296+ ] ,
297+ [
298+ "response_format" ,
299+ JSON . stringify ( { response_format : { type : "json_object" } } ) ,
300+ "settings:validation.openAiExtraBody.reservedKeys keys=response_format" ,
301+ ] ,
302+ ] ) ( "rejects %s with the localized error" , ( _name , openAiExtraBody , expectedError ) => {
303+ const config = createConfig ( openAiExtraBody )
304+
305+ expect ( validateApiConfiguration ( config , mockRouterModels , allowAllOrganization ) ) . toBe ( expectedError )
306+ } )
307+
308+ it ( "returns required-field errors before Extra Body errors" , ( ) => {
309+ const config = createConfig ( "not json" )
310+ config . openAiApiKey = undefined
311+
312+ expect ( validateApiConfiguration ( config , mockRouterModels , allowAllOrganization ) ) . toBe (
313+ "settings:validation.openAi" ,
314+ )
315+ } )
316+ } )
317+
262318 describe ( "Opencode Go validation" , ( ) => {
263319 it ( "returns an apiKey error when the Opencode Go API key is missing" , ( ) => {
264320 const config : ProviderSettings = {
0 commit comments