nic-6443 opened a new pull request, #13251:
URL: https://github.com/apache/apisix/pull/13251

   ### Description
   
   Adds `override.request_body` to `ai-proxy` and `ai-proxy-multi`, letting 
operators set arbitrary nested fields on the outgoing request body, keyed by 
target protocol.
   
   The existing `options` field can only overwrite top-level fields and is 
protocol-agnostic, so it cannot express protocol-specific params such as 
`max_tokens` vs `max_output_tokens` vs `generationConfig.maxOutputTokens`. This 
new field fills that gap without breaking any existing behaviour.
   
   ### Design notes
   
   - **Keyed by target protocol**, not client protocol. Converters only do 
structural format conversion (message layout, SSE event shape); they do not 
semantically normalize parameter names across protocols. So an override like 
\`max_output_tokens\` cannot be matched to the client protocol and expected to 
reach the upstream as-is. The override therefore applies after the converter, 
matched against the protocol actually sent to the provider.
   - **Reuses the existing \`override\` field** instead of introducing a 
parallel \`override_request\`. \`override.endpoint\` and 
\`override.request_body\` are both \"tweaks to the outgoing HTTP request\".
   - **Deep merge for objects, replace for arrays/scalars**, no 
\`null\`-deletion. I walked through every array-shaped parameter in the major 
AI APIs (OpenAI Chat/Responses/Embeddings \`tools\`/\`stop\`/\`include\`, 
Anthropic \`stop_sequences\`/\`system\` blocks, Gemini 
\`safetySettings\`/\`contents\`/\`tools.functionDeclarations\`) and for every 
case where an operator would actually want to override, the semantics is \"my 
list is the list\" — so wholesale array replace is both simplest and the only 
predictable semantics.
   - **Applied after \`options\`**, so if the same key is set in both, 
\`request_body\` wins (more specific beats less specific).
   - **Protocol enum is dynamic**: generated from the registered table in 
\`ai-protocols/init.lua\`, so new protocols added later are picked up 
automatically.
   
   ### Changes
   
   | File | Change |
   |---|---|
   | \`apisix/plugins/ai-proxy/merge.lua\` | New: pure-function deep_merge 
helper |
   | \`apisix/plugins/ai-proxy/schema.lua\` | New \`override.request_body\` 
schema; shared \`override_schema\` DRY-up |
   | \`apisix/plugins/ai-proxy/base.lua\` | Read \`override.request_body\` into 
\`extra_opts\` |
   | \`apisix/plugins/ai-providers/base.lua\` | Deep-merge the matching entry 
into outgoing body after model_options |
   | \`apisix/plugins/ai-protocols/init.lua\` | Expose \`names()\` for schema 
enum generation |
   | \`t/plugin/ai-proxy-request-body-override.t\` | 9 scenarios: schema 
reject, chat override, deep-merge, array replace, precedence over options, 
non-matching protocol key ignored, per-instance in ai-proxy-multi, converter 
path (client anthropic → target openai-chat), backward compat |
   | \`docs/{en,zh}/latest/plugins/ai-proxy*.md\` | New field documented in 
both tables |
   
   ### Example
   
   \`\`\`yaml
   plugins:
     ai-proxy:
       provider: openai
       auth: { header: { Authorization: \"Bearer ...\" } }
       override:
         request_body:
           openai-chat:        { max_tokens: 500, temperature: 0.2 }
           openai-responses:   { max_output_tokens: 500 }
           anthropic-messages: { max_tokens: 500, stop_sequences: [\"Human:\"] }
   \`\`\`
   
   ### Checklist
   
   - [x] Done in a [PR to main branch](CONTRIBUTING.md)
   - [x] Unit tests added (t/plugin/ai-proxy-request-body-override.t)
   - [x] Documentation (both en and zh)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to