Skip to content

Commit 970ba01

Browse files
committed
refactor(ai-proxy): replace per-protocol request_body override with provider capability hooks
Replace the per-protocol keyed request_body override design with a simpler flat schema where users set max_tokens and APISIX automatically maps it to the correct field name via rewrite_request_body hooks in provider capabilities. Config changes from: request_body: { "openai-chat": { max_tokens: 500 } } to: request_body: { max_tokens: 500 } Each provider's capability entry now has a rewrite_request_body(body, override, force) hook that sets the provider-native field: - OpenAI: max_completion_tokens - OpenAI Responses: max_output_tokens - Gemini/Vertex-AI: max_completion_tokens - DeepSeek/Anthropic/OpenRouter/AIMLAPI/Azure/Compatible: max_tokens Removed: - merge.lua (deep merge no longer needed) - protocols.names() (no longer needed by schema)
1 parent 50a2c49 commit 970ba01

19 files changed

Lines changed: 194 additions & 267 deletions

File tree

apisix/plugins/ai-protocols/init.lua

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
local converters = require("apisix.plugins.ai-protocols.converters")
2424
local ipairs = ipairs
25-
local pairs = pairs
2625

2726
local _M = {}
2827

@@ -66,16 +65,6 @@ function _M.get(name)
6665
end
6766

6867

69-
--- Get the list of all registered protocol names.
70-
-- @return table Array of protocol names
71-
function _M.names()
72-
local names = {}
73-
for name in pairs(registered) do
74-
names[#names + 1] = name
75-
end
76-
return names
77-
end
78-
7968

8069
--- Find a converter that can bridge from client_protocol to a protocol
8170
-- supported by the driver. Delegates to the converters registry.

apisix/plugins/ai-providers/aimlapi.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_tokens == nil then
21+
body.max_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
host = "api.aimlapi.com",
2129
port = 443,
2230
capabilities = {
23-
["openai-chat"] = { path = "/chat/completions" },
31+
["openai-chat"] = {
32+
path = "/chat/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
2435
},
2536
}
2637
)

apisix/plugins/ai-providers/anthropic.lua

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,27 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_tokens == nil then
21+
body.max_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
host = "api.anthropic.com",
2129
port = 443,
2230
capabilities = {
23-
["openai-chat"] = { path = "/v1/chat/completions" },
24-
["anthropic-messages"] = { path = "/v1/messages" },
31+
["openai-chat"] = {
32+
path = "/v1/chat/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
35+
["anthropic-messages"] = {
36+
path = "/v1/messages",
37+
rewrite_request_body = rewrite_max_tokens,
38+
},
2539
},
2640
}
2741
)

apisix/plugins/ai-providers/azure-openai.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_tokens == nil then
21+
body.max_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
port = 443,
2129
remove_model = true,
2230
capabilities = {
23-
["openai-chat"] = { path = "/completions" },
31+
["openai-chat"] = {
32+
path = "/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
2435
},
2536
}
2637
)

apisix/plugins/ai-providers/base.lua

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ local transport_http = require("apisix.plugins.ai-transport.http")
3636
local transport_auth = require("apisix.plugins.ai-transport.auth")
3737
local log_sanitize = require("apisix.utils.log-sanitize")
3838
local protocols = require("apisix.plugins.ai-protocols")
39-
local deep_merge = require("apisix.plugins.ai-proxy.merge").deep_merge
4039
local ngx = ngx
4140
local ngx_now = ngx.now
4241

@@ -183,14 +182,12 @@ function _M.build_request(self, ctx, conf, request_body, opts)
183182
end
184183
end
185184

186-
-- Inject per-target-protocol request body override (deep merge)
187-
if opts.request_body_override_map then
188-
local patch = opts.request_body_override_map[ctx.ai_target_protocol]
189-
if patch then
190-
core.log.info("applying request_body override for target protocol '",
191-
ctx.ai_target_protocol, "'")
192-
request_body = deep_merge(request_body, patch,
193-
opts.request_body_force_override)
185+
-- Apply request body override via provider capability hook
186+
if opts.override_request_body then
187+
local cap = self.capabilities and self.capabilities[ctx.ai_target_protocol]
188+
if cap and cap.rewrite_request_body then
189+
cap.rewrite_request_body(request_body, opts.override_request_body,
190+
opts.request_body_force_override)
194191
end
195192
end
196193
params.body = request_body

apisix/plugins/ai-providers/deepseek.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_tokens == nil then
21+
body.max_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
host = "api.deepseek.com",
2129
port = 443,
2230
capabilities = {
23-
["openai-chat"] = { path = "/chat/completions" },
31+
["openai-chat"] = {
32+
path = "/chat/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
2435
},
2536
}
2637
)

apisix/plugins/ai-providers/gemini.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_completion_tokens == nil then
21+
body.max_completion_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
host = "generativelanguage.googleapis.com",
2129
port = 443,
2230
capabilities = {
23-
["openai-chat"] = { path = "/v1beta/openai/chat/completions" },
31+
["openai-chat"] = {
32+
path = "/v1beta/openai/chat/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
2435
},
2536
}
2637
)

apisix/plugins/ai-providers/openai-compatible.lua

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,26 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(field_name)
19+
return function(body, override, force)
20+
if override.max_tokens then
21+
if force or body[field_name] == nil then
22+
body[field_name] = override.max_tokens
23+
end
24+
end
25+
end
26+
end
27+
1828
return require("apisix.plugins.ai-providers.base").new({
1929
capabilities = {
20-
["openai-chat"] = { path = "/v1/chat/completions" },
21-
["openai-responses"] = { path = "/v1/responses" },
30+
["openai-chat"] = {
31+
path = "/v1/chat/completions",
32+
rewrite_request_body = rewrite_max_tokens("max_tokens"),
33+
},
34+
["openai-responses"] = {
35+
path = "/v1/responses",
36+
rewrite_request_body = rewrite_max_tokens("max_output_tokens"),
37+
},
2238
["openai-embeddings"] = { path = "/v1/embeddings" },
2339
},
2440
})

apisix/plugins/ai-providers/openai.lua

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,29 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(field_name)
19+
return function(body, override, force)
20+
if override.max_tokens then
21+
if force or body[field_name] == nil then
22+
body[field_name] = override.max_tokens
23+
end
24+
end
25+
end
26+
end
27+
1828
return require("apisix.plugins.ai-providers.base").new(
1929
{
2030
host = "api.openai.com",
2131
port = 443,
2232
capabilities = {
23-
["openai-chat"] = { path = "/v1/chat/completions" },
24-
["openai-responses"] = { path = "/v1/responses" },
33+
["openai-chat"] = {
34+
path = "/v1/chat/completions",
35+
rewrite_request_body = rewrite_max_tokens("max_completion_tokens"),
36+
},
37+
["openai-responses"] = {
38+
path = "/v1/responses",
39+
rewrite_request_body = rewrite_max_tokens("max_output_tokens"),
40+
},
2541
["openai-embeddings"] = { path = "/v1/embeddings" },
2642
},
2743
}

apisix/plugins/ai-providers/openrouter.lua

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,23 @@
1515
-- limitations under the License.
1616
--
1717

18+
local function rewrite_max_tokens(body, override, force)
19+
if override.max_tokens then
20+
if force or body.max_tokens == nil then
21+
body.max_tokens = override.max_tokens
22+
end
23+
end
24+
end
25+
1826
return require("apisix.plugins.ai-providers.base").new(
1927
{
2028
host = "openrouter.ai",
2129
port = 443,
2230
capabilities = {
23-
["openai-chat"] = { path = "/api/v1/chat/completions" },
31+
["openai-chat"] = {
32+
path = "/api/v1/chat/completions",
33+
rewrite_request_body = rewrite_max_tokens,
34+
},
2435
},
2536
}
2637
)

0 commit comments

Comments
 (0)