Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion apisix/plugins/ai-providers/base.lua
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,20 @@ function _M.build_request(self, ctx, conf, request_body, opts)
ctx.ai_converter.convert_headers(headers)
end

-- For the passthrough protocol the gateway acts as a catch-all proxy, so
-- forward the client's HTTP method and original query string unchanged.
-- Other protocols always issue a POST with provider-specific query args.
local method = "POST"
if ctx.ai_target_protocol == "passthrough" then
method = core.request.get_method()
local client_args = ctx.var.args and core.string.decode_args(ctx.var.args)
if type(client_args) == "table" then
core.table.merge(query_params, client_args)
end
end

local params = {
method = "POST",
method = method,
scheme = scheme,
headers = headers,
ssl_verify = conf.ssl_verify,
Expand Down
153 changes: 153 additions & 0 deletions t/plugin/ai-proxy-passthrough.t
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,156 @@ images: passthrough
empty: nil
--- no_error_log
no matching AI protocol



=== TEST 10: set route for passthrough query/method forwarding
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/plugin_proxy_rewrite_args",
"plugins": {
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer token"
}
},
"override": {
"endpoint": "http://127.0.0.1:1980"
},
"ssl_verify": false
}
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 11: passthrough forwards the client query string to the upstream
--- request
POST /plugin_proxy_rewrite_args?name=foo
{"prompt":"x"}
--- more_headers
Content-Type: application/json
--- response_body eval
qr/name: foo/
--- no_error_log
no matching AI protocol



=== TEST 12: set route for passthrough method forwarding
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/plugin_proxy_rewrite",
"plugins": {
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer token"
}
},
"override": {
"endpoint": "http://127.0.0.1:1980"
},
"ssl_verify": false
}
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 13: passthrough forwards the client HTTP method to the upstream
--- request
PUT /plugin_proxy_rewrite
{"prompt":"x"}
--- more_headers
Content-Type: application/json
--- error_log
plugin_proxy_rewrite get method: PUT
--- no_error_log
no matching AI protocol



=== TEST 14: set route whose override.endpoint carries its own query args
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"uri": "/plugin_proxy_rewrite_args",
"plugins": {
"ai-proxy": {
"provider": "openai",
"auth": {
"header": {
"Authorization": "Bearer token"
}
},
"override": {
"endpoint": "http://127.0.0.1:1980/plugin_proxy_rewrite_args?name=fromendpoint&ekey=eval"
},
"ssl_verify": false
}
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed



=== TEST 15: client query overrides the endpoint query on conflicting keys
--- request
POST /plugin_proxy_rewrite_args?name=fromclient&ckey=cval
{"prompt":"x"}
--- more_headers
Content-Type: application/json
--- response_body
uri: /plugin_proxy_rewrite_args
ckey: cval
ekey: eval
name: fromclient
--- no_error_log
no matching AI protocol
Loading