This is an automated email from the ASF dual-hosted git repository.

ashishtiwari pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new de03766ea fix(ai-proxy): check type of choices/usage/content fields 
before use it (#12548)
de03766ea is described below

commit de03766eaef9e000d58baf7766cb55225b12c69f
Author: Ashish Tiwari <ashishjaitiwari15112...@gmail.com>
AuthorDate: Thu Aug 28 13:11:52 2025 +0530

    fix(ai-proxy): check type of choices/usage/content fields before use it 
(#12548)
---
 apisix/plugins/ai-drivers/openai-base.lua | 21 +++++----
 t/plugin/ai-proxy3.t                      | 71 +++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 9 deletions(-)

diff --git a/apisix/plugins/ai-drivers/openai-base.lua 
b/apisix/plugins/ai-drivers/openai-base.lua
index 4607cbca8..0b105d729 100644
--- a/apisix/plugins/ai-drivers/openai-base.lua
+++ b/apisix/plugins/ai-drivers/openai-base.lua
@@ -163,17 +163,20 @@ local function read_response(ctx, res)
             ", it will cause token usage not available")
     else
         core.log.info("got token usage from ai service: ", 
core.json.delay_encode(res_body.usage))
-        ctx.ai_token_usage = {
-            prompt_tokens = res_body.usage and res_body.usage.prompt_tokens or 
0,
-            completion_tokens = res_body.usage and 
res_body.usage.completion_tokens or 0,
-            total_tokens = res_body.usage and res_body.usage.total_tokens or 0,
-        }
-        ctx.var.llm_prompt_tokens = ctx.ai_token_usage.prompt_tokens
-        ctx.var.llm_completion_tokens = ctx.ai_token_usage.completion_tokens
-        if res_body.choices and #res_body.choices > 0 then
+        ctx.ai_token_usage = {}
+        if type(res_body.usage) == "table" then
+            ctx.ai_token_usage.prompt_tokens = res_body.usage.prompt_tokens or 0
+            ctx.ai_token_usage.completion_tokens = 
res_body.usage.completion_tokens or 0
+            ctx.ai_token_usage.total_tokens = res_body.usage.total_tokens or 0
+        end
+        ctx.var.llm_prompt_tokens = ctx.ai_token_usage.prompt_tokens or 0
+        ctx.var.llm_completion_tokens = ctx.ai_token_usage.completion_tokens 
or 0
+        if type(res_body.choices) == "table" and #res_body.choices > 0 then
             local contents = {}
             for _, choice in ipairs(res_body.choices) do
-                if choice and choice.message and choice.message.content then
+                if type(choice) == "table"
+                        and type(choice.message) == "table"
+                        and type(choice.message.content) == "string" then
                     core.table.insert(contents, choice.message.content)
                 end
             end
diff --git a/t/plugin/ai-proxy3.t b/t/plugin/ai-proxy3.t
index 3e39f5d39..ec771f690 100644
--- a/t/plugin/ai-proxy3.t
+++ b/t/plugin/ai-proxy3.t
@@ -87,6 +87,30 @@ add_block_preprocessor(sub {
     "completion_tokens": 20,
     "total_tokens": 30
   }
+}]]
+                    ngx.status = 200
+                    ngx.say(res)
+                }
+            }
+
+            location /null-content {
+                content_by_lua_block {
+                    local json = require("cjson.safe")
+
+            local res = [[
+{
+  "model": "gpt-3.5-turbo",
+  "choices": [
+    {
+      "index": 0,
+      "message": {
+        "role": "assistant",
+        "content": null
+      },
+      "finish_reason": "stop"
+    }
+  ],
+  "usage": null
 }]]
                     ngx.status = 200
                     ngx.say(res)
@@ -153,3 +177,50 @@ POST /anything
 qr/.*completion_tokens.*/
 --- access_log eval
 qr/.*gpt-3.5-turbo \d+ 10 20.*/
+
+
+
+=== TEST 3: proxy to /null-content ai endpoint
+--- 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": "/anything",
+                    "plugins": {
+                        "ai-proxy": {
+                            "provider": "openai",
+                            "auth": {
+                                "header": {
+                                    "Authorization": "Bearer token"
+                                }
+                            },
+                            "override": {
+                                "endpoint": 
"http://localhost:6724/null-content";
+                            }
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 4: send request
+--- request
+POST /anything
+{"messages":[{"role":"user","content":"What is 1+1?"}], "model": "gpt-4"}
+--- error_code: 200
+--- response_body eval
+qr/.*assistant.*/
+--- no_error_log

Reply via email to