local helpers = require "spec.helpers" local cjson = require "cjson" local pl_file = require "pl.file" local PLUGIN_NAME = "ai-proxy" for _, strategy in helpers.all_strategies() do describe(PLUGIN_NAME .. ": (access) [#" .. strategy .. "]", function() local client local MOCK_PORT lazy_setup(function() MOCK_PORT = helpers.get_available_port() local bp = helpers.get_db_utils(strategy == "off" and "postgres" or strategy, nil, { PLUGIN_NAME }) -- set up mistral mock fixtures local fixtures = { http_mock = {}, } fixtures.http_mock.llama2 = [[ server { server_name llama2; listen ]]..MOCK_PORT..[[; default_type 'application/json'; location = "/raw/llm/v1/chat" { content_by_lua_block { local pl_file = require "pl.file" local json = require("cjson.safe") local token = ngx.req.get_headers()["authorization"] if token == "Bearer llama2-key" then ngx.req.read_body() local body, err = ngx.req.get_body_data() body, err = json.decode(body) if (err) or (not body) or (not body.inputs) or (body.inputs == ngx.null) or (not string.find((body and body.inputs) or "", "INST")) then ngx.status = 400 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/bad_request.json")) else ngx.status = 200 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/good.json")) end else ngx.status = 401 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/unauthorized.json")) end } } location = "/raw/llm/v1/completions" { content_by_lua_block { local pl_file = require "pl.file" local json = require("cjson.safe") local token = ngx.req.get_headers()["authorization"] if token == "Bearer llama2-key" then ngx.req.read_body() local body, err = ngx.req.get_body_data() body, err = json.decode(body) if (err) or (not body) or (not body.inputs) or (body.inputs == ngx.null) or (not string.find((body and body.inputs) or "", "INST")) then ngx.status = 400 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/bad_request.json")) else ngx.status = 200 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/good.json")) end else ngx.status = 401 ngx.print(pl_file.read("spec/fixtures/ai-proxy/llama2/raw/responses/unauthorized.json")) end } } } ]] local empty_service = assert(bp.services:insert { name = "empty_service", host = "localhost", --helpers.mock_upstream_host, port = 8080, --MOCK_PORT, path = "/", }) -- 200 chat good with one option local chat_good = assert(bp.routes:insert { service = empty_service, protocols = { "http" }, strip_path = true, paths = { "/raw/llm/v1/chat/completions" } }) bp.plugins:insert { name = PLUGIN_NAME, route = { id = chat_good.id }, config = { route_type = "llm/v1/chat", auth = { header_name = "Authorization", header_value = "Bearer llama2-key", }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 256, temperature = 1.0, llama2_format = "raw", upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/chat", }, }, }, } -- -- 200 completions good with one option local chat_good = assert(bp.routes:insert { service = empty_service, protocols = { "http" }, strip_path = true, paths = { "/raw/llm/v1/completions" } }) bp.plugins:insert { name = PLUGIN_NAME, route = { id = chat_good.id }, config = { route_type = "llm/v1/completions", auth = { header_name = "Authorization", header_value = "Bearer llama2-key", allow_override = true, }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 256, temperature = 1.0, llama2_format = "raw", upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/completions", }, }, }, } local chat_good_no_allow_override = assert(bp.routes:insert { service = empty_service, protocols = { "http" }, strip_path = true, paths = { "/raw/llm/v1/completions-no-allow-override" } }) bp.plugins:insert { name = PLUGIN_NAME, route = { id = chat_good_no_allow_override.id }, config = { route_type = "llm/v1/completions", auth = { header_name = "Authorization", header_value = "Bearer llama2-key", allow_override = false, }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 256, temperature = 1.0, llama2_format = "raw", upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/completions", }, }, }, } -- -- start kong assert(helpers.start_kong({ -- set the strategy database = strategy, -- use the custom test template to create a local mock server nginx_conf = "spec/fixtures/custom_nginx.template", -- make sure our plugin gets loaded plugins = "bundled," .. PLUGIN_NAME, -- write & load declarative config, only if 'strategy=off' declarative_config = strategy == "off" and helpers.make_yaml_file() or nil, }, nil, nil, fixtures)) end) lazy_teardown(function() helpers.stop_kong() end) before_each(function() client = helpers.proxy_client() end) after_each(function() if client then client:close() end end) describe("llama2 general", function() it("runs good request in chat format", function() local r = client:get("/raw/llm/v1/chat/completions", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-chat.json"), }) local body = assert.res_status(200, r) local json = cjson.decode(body) assert.equals(json.choices[1].message.content, "Is a well known font.") end) it("runs good request in completions format", function() local r = client:get("/raw/llm/v1/completions", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-completions.json"), }) local body = assert.res_status(200, r) local json = cjson.decode(body) assert.equals(json.choices[1].text, "Is a well known font.") end) it("runs good request in completions format with client right auth", function() local r = client:get("/raw/llm/v1/completions", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", ["Authorization"] = "Bearer llama2-key" }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-completions.json"), }) local body = assert.res_status(200, r) local json = cjson.decode(body) assert.equals(json.choices[1].text, "Is a well known font.") end) it("runs good request in completions format with client wrong auth", function() local r = client:get("/raw/llm/v1/completions", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", ["Authorization"] = "Bearer wrong" }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-completions.json"), }) local body = assert.res_status(401, r) local json = cjson.decode(body) assert.equals(json.error, "Model requires a Pro subscription.") end) it("runs good request in completions format with client right auth and no allow_override", function() local r = client:get("/raw/llm/v1/completions-no-allow-override", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", ["Authorization"] = "Bearer llama2-key" }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-completions.json"), }) local body = assert.res_status(200, r) local json = cjson.decode(body) assert.equals(json.choices[1].text, "Is a well known font.") end) it("runs good request in completions format with client wrong auth and no allow_override", function() local r = client:get("/raw/llm/v1/completions-no-allow-override", { headers = { ["content-type"] = "application/json", ["accept"] = "application/json", ["Authorization"] = "Bearer wrong" }, body = pl_file.read("spec/fixtures/ai-proxy/llama2/raw/requests/good-completions.json"), }) local body = assert.res_status(200, r) local json = cjson.decode(body) assert.equals(json.choices[1].text, "Is a well known font.") end) end) describe("one-shot request", function() it("success", function() local ai_driver = require("kong.llm.drivers.llama2") local plugin_conf = { route_type = "llm/v1/chat", auth = { header_name = "Authorization", header_value = "Bearer llama2-key", }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 1024, upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/chat", llama2_format = "raw", }, }, } local request = { messages = { [1] = { role = "system", content = "Some system prompt", }, [2] = { role = "user", content = "Some question", } } } -- convert it to the specified driver format local ai_request, content_type, err = ai_driver.to_format(request, plugin_conf.model, "llm/v1/chat") assert.is_nil(err) assert.is_not_nil(content_type) -- send it to the ai service local ai_response, status_code, err = ai_driver.subrequest(ai_request, plugin_conf, {}, false) assert.equal(200, status_code) assert.is_nil(err) -- parse and convert the response local ai_response, _, err = ai_driver.from_format(ai_response, plugin_conf.model, plugin_conf.route_type) assert.is_nil(err) -- check it local response_table, err = cjson.decode(ai_response) assert.is_nil(err) assert.same(response_table.choices[1].message, { content = "Is a well known font.", role = "assistant", }) end) it("404", function() local ai_driver = require("kong.llm.drivers.llama2") local plugin_conf = { route_type = "llm/v1/chat", auth = { header_name = "Authorization", header_value = "Bearer llama2-key", }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 1024, upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/nowhere", llama2_format = "raw", }, }, } local request = { messages = { [1] = { role = "system", content = "Some system prompt", }, [2] = { role = "user", content = "Some question", } } } -- convert it to the specified driver format local ai_request = ai_driver.to_format(request, plugin_conf.model, "llm/v1/chat") -- send it to the ai service local ai_response, status_code, err = ai_driver.subrequest(ai_request, plugin_conf, {}, false) assert.is_not_nil(err) assert.is_not_nil(ai_response) assert.equal(404, status_code) end) it("401", function() local ai_driver = require("kong.llm.drivers.llama2") local plugin_conf = { route_type = "llm/v1/chat", auth = { header_name = "Authorization", header_value = "Bearer wrong-key", }, model = { name = "llama-2-7b-chat-hf", provider = "llama2", options = { max_tokens = 1024, upstream_url = "http://"..helpers.mock_upstream_host..":"..MOCK_PORT.."/raw/llm/v1/chat", llama2_format = "raw", }, }, } local request = { messages = { [1] = { role = "system", content = "Some system prompt", }, [2] = { role = "user", content = "Some question", } } } -- convert it to the specified driver format local ai_request = ai_driver.to_format(request, plugin_conf.model, "llm/v1/chat") -- send it to the ai service local ai_response, status_code, err = ai_driver.subrequest(ai_request, plugin_conf, {}, false) assert.is_not_nil(err) assert.is_not_nil(ai_response) assert.equal(401, status_code) end) end) end) end