205 lines
6.7 KiB
Lua
205 lines
6.7 KiB
Lua
local PLUGIN_NAME = "ai-proxy"
|
|
local pl_file = require("pl.file")
|
|
local cjson = require("cjson.safe")
|
|
local fmt = string.format
|
|
|
|
|
|
local _NATIVE_ADAPTERS = {
|
|
bedrock = {
|
|
CLASS = "kong.llm.adapters.bedrock",
|
|
TESTS = {
|
|
["GOOD_FULL_NO_STREAM"] = {
|
|
INPUT_FILE = "spec/fixtures/ai-proxy/native/bedrock/request/with-functions-and-chatter.json",
|
|
CLEANUP_BEFORE_COMPARE = function(expected_response, real_response)
|
|
expected_response.model = "cohere.command-r-v1:0"
|
|
return expected_response, real_response
|
|
end,
|
|
MOCK_KONG = {
|
|
request = {
|
|
get_path = function()
|
|
return "/bedrock/model/cohere.command-r-v1%3A0/converse"
|
|
end,
|
|
get_uri_captures = function()
|
|
return {
|
|
named = {
|
|
["model"] = "cohere.command-r-v1:0",
|
|
["operation"] = "converse",
|
|
},
|
|
}
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
["GOOD_FULL_WITH_STREAM"] = {
|
|
INPUT_FILE = "spec/fixtures/ai-proxy/native/bedrock/request/with-functions-and-chatter.json",
|
|
CLEANUP_BEFORE_COMPARE = function(expected_response, real_response)
|
|
expected_response.model = "cohere.command-r-v1:0"
|
|
return expected_response, real_response
|
|
end,
|
|
MOCK_KONG = {
|
|
request = {
|
|
get_path = function()
|
|
return "/bedrock/model/cohere.command-r-v1%3A0/converse-stream"
|
|
end,
|
|
get_uri_captures = function()
|
|
return {
|
|
named = {
|
|
["model"] = "cohere.command-r-v1:0",
|
|
["operation"] = "converse-stream",
|
|
},
|
|
}
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
gemini = {
|
|
CLASS = "kong.llm.adapters.gemini",
|
|
TESTS = {
|
|
["GOOD_FULL_NO_STREAM"] = {
|
|
INPUT_FILE = "spec/fixtures/ai-proxy/native/gemini/request/with-functions-and-chatter.json",
|
|
CLEANUP_BEFORE_COMPARE = function(expected_response, real_response)
|
|
for i, v in ipairs(expected_response.messages) do
|
|
if v.tool_call_id then
|
|
expected_response.messages[i].tool_call_id = nil
|
|
end
|
|
if v.tool_calls then
|
|
for j, k in ipairs(v.tool_calls) do
|
|
expected_response.messages[i].tool_calls[j].id = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
for i, v in ipairs(real_response.messages) do
|
|
if v.tool_calls then
|
|
for j, k in ipairs(v.tool_calls) do
|
|
real_response.messages[i].tool_calls[j]['function'].id = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
return expected_response, real_response
|
|
end,
|
|
MOCK_KONG = {
|
|
request = {
|
|
get_path = function()
|
|
return "/v1/projects/fake-project-010101/locations/us-central1/publishers/google/models/gemini-1.5-pro:generateContent"
|
|
end,
|
|
get_uri_captures = function()
|
|
return {
|
|
named = {
|
|
["model"] = "gemini-1.5-pro",
|
|
["operation"] = "generateContent",
|
|
},
|
|
}
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
["GOOD_FULL_WITH_STREAM"] = {
|
|
INPUT_FILE = "spec/fixtures/ai-proxy/native/gemini/request/with-functions-and-chatter.json",
|
|
CLEANUP_BEFORE_COMPARE = function(expected_response, real_response)
|
|
for i, v in ipairs(expected_response.messages) do
|
|
if v.tool_call_id then
|
|
expected_response.messages[i].tool_call_id = nil
|
|
end
|
|
if v.tool_calls then
|
|
for j, k in ipairs(v.tool_calls) do
|
|
expected_response.messages[i].tool_calls[j].id = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
for i, v in ipairs(real_response.messages) do
|
|
if v.tool_calls then
|
|
for j, k in ipairs(v.tool_calls) do
|
|
real_response.messages[i].tool_calls[j]['function'].id = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
return expected_response, real_response
|
|
end,
|
|
MOCK_KONG = {
|
|
request = {
|
|
get_path = function()
|
|
return "/v1/projects/fake-project-010101/locations/us-central1/publishers/google/models/gemini-1.5-pro:streamGenerateContent"
|
|
end,
|
|
get_uri_captures = function()
|
|
return {
|
|
named = {
|
|
["model"] = "gemini-1.5-pro",
|
|
["operation"] = "streamGenerateContent",
|
|
},
|
|
}
|
|
end,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
local COMPARE_OUTPUT_FILES = {
|
|
["GOOD_FULL_NO_STREAM"] = "spec/fixtures/ai-proxy/native/target/target-openai-complete.json",
|
|
["GOOD_FULL_WITH_STREAM"] = "spec/fixtures/ai-proxy/native/target/target-openai-complete-stream.json",
|
|
}
|
|
|
|
|
|
describe(PLUGIN_NAME .. ": (unit)", function()
|
|
lazy_setup(function()
|
|
package.loaded["kong.llm.drivers.shared"] = nil
|
|
_G.TEST = true
|
|
end)
|
|
|
|
lazy_teardown(function()
|
|
_G.TEST = nil
|
|
end)
|
|
|
|
for adapter_name, adapter_manifest in pairs(_NATIVE_ADAPTERS) do
|
|
it(fmt("adapters.%s good full no stream", adapter_name), function()
|
|
local target_response = cjson.decode(pl_file.read(COMPARE_OUTPUT_FILES.GOOD_FULL_NO_STREAM))
|
|
|
|
local test_manifest = adapter_manifest.TESTS.GOOD_FULL_NO_STREAM
|
|
|
|
package.loaded[adapter_manifest.CLASS] = nil
|
|
_G.TEST = true
|
|
local adapter = require(adapter_manifest.CLASS)
|
|
|
|
adapter = adapter:new()
|
|
|
|
local request = cjson.decode(pl_file.read(test_manifest.INPUT_FILE))
|
|
local response = adapter:to_kong_req(request, test_manifest.MOCK_KONG)
|
|
|
|
if test_manifest.CLEANUP_BEFORE_COMPARE then
|
|
target_response, response = test_manifest.CLEANUP_BEFORE_COMPARE(target_response, response)
|
|
end
|
|
|
|
assert.same(target_response, response)
|
|
end)
|
|
|
|
it(fmt("adapters.%s good full with stream", adapter_name), function()
|
|
local target_response = cjson.decode(pl_file.read(COMPARE_OUTPUT_FILES.GOOD_FULL_WITH_STREAM))
|
|
|
|
local test_manifest = adapter_manifest.TESTS.GOOD_FULL_WITH_STREAM
|
|
|
|
package.loaded[adapter_manifest.CLASS] = nil
|
|
_G.TEST = true
|
|
local adapter = require(adapter_manifest.CLASS)
|
|
|
|
adapter = adapter:new()
|
|
|
|
local request = cjson.decode(pl_file.read(test_manifest.INPUT_FILE))
|
|
local response = adapter:to_kong_req(request, test_manifest.MOCK_KONG)
|
|
|
|
if test_manifest.CLEANUP_BEFORE_COMPARE then
|
|
target_response, response = test_manifest.CLEANUP_BEFORE_COMPARE(target_response, response)
|
|
end
|
|
|
|
assert.same(target_response, response)
|
|
end)
|
|
end
|
|
|
|
end)
|