diff --git a/spec/03-plugins/38-ai-proxy/03-anthropic_integration_spec.lua b/spec/03-plugins/38-ai-proxy/03-anthropic_integration_spec.lua index dd52f7e066a9..6d87425054e8 100644 --- a/spec/03-plugins/38-ai-proxy/03-anthropic_integration_spec.lua +++ b/spec/03-plugins/38-ai-proxy/03-anthropic_integration_spec.lua @@ -218,6 +218,35 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, }, } + + local chat_good_no_allow_override = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "/anthropic/llm/v1/chat/good-no-allow-override" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_good_no_allow_override.id }, + config = { + route_type = "llm/v1/chat", + auth = { + header_name = "x-api-key", + header_value = "anthropic-key", + allow_auth_override = false, + }, + model = { + name = "claude-2.1", + provider = "anthropic", + options = { + max_tokens = 256, + temperature = 1.0, + upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/llm/v1/chat/good", + anthropic_version = "2023-06-01", + }, + }, + }, + } -- -- 200 chat bad upstream response with one option @@ -551,6 +580,105 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, json.choices[1].message) end) + it("good request with client right header auth", function() + local r = client:get("/anthropic/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["x-api-key"] = "anthropic-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/anthropic/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + -- assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "claude-2.1") + assert.equals(json.object, "chat.content") + assert.equals(r.headers["X-Kong-LLM-Model"], "anthropic/claude-2.1") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with client wrong header auth", function() + local r = client:get("/anthropic/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["x-api-key"] = "wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/anthropic/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(401 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.is_truthy(json.error) + assert.equals(json.error.type, "authentication_error") + end) + + it("good request with client right header auth and no allow_auth_override", function() + local r = client:get("/anthropic/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["x-api-key"] = "anthropic-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/anthropic/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + -- assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "claude-2.1") + assert.equals(json.object, "chat.content") + assert.equals(r.headers["X-Kong-LLM-Model"], "anthropic/claude-2.1") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with client wrong header auth and no allow_auth_override", function() + local r = client:get("/anthropic/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["x-api-key"] = "wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/anthropic/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + -- assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "claude-2.1") + assert.equals(json.object, "chat.content") + assert.equals(r.headers["X-Kong-LLM-Model"], "anthropic/claude-2.1") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + it("bad upstream response", function() local r = client:get("/anthropic/llm/v1/chat/bad_upstream_response", { headers = { diff --git a/spec/03-plugins/38-ai-proxy/04-cohere_integration_spec.lua b/spec/03-plugins/38-ai-proxy/04-cohere_integration_spec.lua index eb52249c8fb4..d3d0f55a9ce9 100644 --- a/spec/03-plugins/38-ai-proxy/04-cohere_integration_spec.lua +++ b/spec/03-plugins/38-ai-proxy/04-cohere_integration_spec.lua @@ -166,6 +166,33 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, }, } + local chat_good_no_allow_override = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "/cohere/llm/v1/chat/good-no-allow-override" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_good_no_allow_override.id }, + config = { + route_type = "llm/v1/chat", + auth = { + header_name = "Authorization", + header_value = "Bearer cohere-key", + allow_auth_override = false, + }, + model = { + name = "command", + provider = "cohere", + options = { + max_tokens = 256, + temperature = 1.0, + upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/llm/v1/chat/good", + }, + }, + }, + } -- -- 200 chat bad upstream response with one option @@ -426,6 +453,102 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, json.choices[1].message) end) + it("good request with right client auth", function() + local r = client:get("/cohere/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["Authorization"] = "Bearer cohere-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/cohere/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.model, "command") + assert.equals(json.object, "chat.completion") + assert.equals(r.headers["X-Kong-LLM-Model"], "cohere/command") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with wrong client auth", function() + local r = client:get("/cohere/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["Authorization"] = "Bearer wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/cohere/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(401 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.is_truthy(json.message) + assert.equals(json.message, "invalid api token") + end) + + it("good request with right client auth and no allow_auth_override", function() + local r = client:get("/cohere/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["Authorization"] = "Bearer cohere-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/cohere/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.model, "command") + assert.equals(json.object, "chat.completion") + assert.equals(r.headers["X-Kong-LLM-Model"], "cohere/command") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with wrong client auth and no allow_auth_override", function() + local r = client:get("/cohere/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["Authorization"] = "Bearer wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/cohere/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.model, "command") + assert.equals(json.object, "chat.completion") + assert.equals(r.headers["X-Kong-LLM-Model"], "cohere/command") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + it("bad upstream response", function() local r = client:get("/cohere/llm/v1/chat/bad_upstream_response", { headers = { diff --git a/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua b/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua index 82385720efcf..baa6a618389d 100644 --- a/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua +++ b/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua @@ -168,6 +168,36 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, }, } + + local chat_good_no_allow_override = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "/azure/llm/v1/chat/good-no-allow-override" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_good_no_allow_override.id }, + config = { + route_type = "llm/v1/chat", + auth = { + header_name = "api-key", + header_value = "azure-key", + allow_auth_override = false, + }, + model = { + name = "gpt-3.5-turbo", + provider = "azure", + options = { + max_tokens = 256, + temperature = 1.0, + upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/llm/v1/chat/good", + azure_instance = "001-kong-t", + azure_deployment_id = "gpt-3.5-custom", + }, + }, + }, + } -- -- 200 chat bad upstream response with one option @@ -442,6 +472,105 @@ for _, strategy in helpers.all_strategies() do if strategy ~= "cassandra" then }, json.choices[1].message) end) + it("good request with client right auth", function() + local r = client:get("/azure/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["api-key"] = "azure-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- validate that the request succeeded, response status 200 + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "gpt-3.5-turbo-0613") + assert.equals(json.object, "chat.completion") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with client wrong auth", function() + local r = client:get("/azure/llm/v1/chat/good", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["api-key"] = "wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + local body = assert.res_status(401 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.is_truthy(json.error) + assert.equals(json.error.code, "invalid_api_key") + end) + + it("good request with client right auth and no allow_auth_override", function() + local r = client:get("/azure/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["api-key"] = "azure-key", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- validate that the request succeeded, response status 200 + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "gpt-3.5-turbo-0613") + assert.equals(json.object, "chat.completion") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + + it("good request with client wrong auth and no allow_auth_override", function() + local r = client:get("/azure/llm/v1/chat/good-no-allow-override", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + ["api-key"] = "wrong", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- validate that the request succeeded, response status 200 + local body = assert.res_status(200 , r) + local json = cjson.decode(body) + + -- check this is in the 'kong' response format + assert.equals(json.id, "chatcmpl-8T6YwgvjQVVnGbJ2w8hpOA17SeNy2") + assert.equals(json.model, "gpt-3.5-turbo-0613") + assert.equals(json.object, "chat.completion") + + assert.is_table(json.choices) + assert.is_table(json.choices[1].message) + assert.same({ + content = "The sum of 1 + 1 is 2.", + role = "assistant", + }, json.choices[1].message) + end) + it("bad upstream response", function() local r = client:get("/azure/llm/v1/chat/bad_upstream_response", { headers = {