feat: add support for openrouter#12878
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds support for the OpenRouter AI provider to APISIX's AI proxy plugins. OpenRouter is added as a new provider option alongside existing providers like OpenAI, DeepSeek, Azure, and AIMLAPI. The implementation follows the established pattern for OpenAI-compatible providers.
Changes:
- Adds OpenRouter driver using the OpenAI-compatible base driver with endpoint
https://openrouter.ai/api/v1/chat/completions - Updates plugin schemas to include "openrouter" as a valid provider option
- Updates both English and Chinese documentation to reflect the new provider
- Adds comprehensive test coverage for the OpenRouter integration
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| t/plugin/ai-proxy-openrouter.t | Adds test suite for OpenRouter provider with authentication, streaming, and basic functionality tests |
| apisix/plugins/ai-drivers/openrouter.lua | New driver implementation for OpenRouter using OpenAI-compatible base |
| apisix/plugins/ai-drivers/schema.lua | Updates schema to include OpenRouter in provider lists and compatibility checks |
| apisix/plugins/ai-proxy/schema.lua | Adds "openrouter" to valid provider enums in both multi and single instance schemas |
| apisix/plugins/ai-request-rewrite.lua | Adds "openrouter" to the provider enum for AI request rewriting |
| docs/en/latest/plugins/ai-request-rewrite.md | Documents OpenRouter as available provider option (with typo fix needed) |
| docs/en/latest/plugins/ai-proxy.md | Documents OpenRouter provider with endpoint details (with typo fix needed) |
| docs/en/latest/plugins/ai-proxy-multi.md | Documents OpenRouter in multi-instance plugin configuration (with typo fix needed) |
| docs/zh/latest/plugins/ai-request-rewrite.md | Chinese translation with OpenRouter documentation (with typo fix needed) |
| docs/zh/latest/plugins/ai-proxy.md | Chinese translation with OpenRouter documentation |
| docs/zh/latest/plugins/ai-proxy-multi.md | Chinese translation with OpenRouter documentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "stream": true | ||
| }, | ||
| "override": { | ||
| "endpoint": "http://localhost:7737/v1/chat/completions" |
There was a problem hiding this comment.
The endpoint port in TEST 3 is set to 7737, but the mock server in the http_config listens on port 6724. This mismatch will cause the test to fail as it won't be able to connect to the mock server.
| "endpoint": "http://localhost:7737/v1/chat/completions" | |
| "endpoint": "http://localhost:6724/v1/chat/completions" |
| | ------------------------- | ------------ | -------- | ------------------------------------------------------------------------------------ | | ||
| | prompt | Yes | String | The prompt send to LLM service. | | ||
| | provider | Yes | String | Name of the LLM service. Available options: openai, deekseek, azure-openai, aimlapi and openai-compatible. When `aimlapi` is selected, the plugin uses the OpenAI-compatible driver with a default endpoint of `https://api.aimlapi.com/v1/chat/completions`. | | ||
| | provider | Yes | String | Name of the LLM service. Available options: openai, deekseek, azure-openai, aimlapi, openrouter and openai-compatible. When `aimlapi` is selected, the plugin uses the OpenAI-compatible driver with a default endpoint of `https://api.aimlapi.com/v1/chat/completions`. | |
There was a problem hiding this comment.
There is a typo in "deekseek" - it should be "deepseek" for consistency with the actual provider name used throughout the codebase.
There was a problem hiding this comment.
This should be fixed in another pr.
| | ------------------------- | ------------ | -------- | ------------------------------------------------------------------------------------ | | ||
| | prompt | 是 | String | 发送到 LLM 服务的提示。 | | ||
| | provider | 是 | String | LLM 服务的名称。可用选项:openai、deekseek、azure-openai、aimlapi 和 openai-compatible。当选择 `aimlapi` 时,插件使用 OpenAI 兼容驱动程序,默认端点为 `https://api.aimlapi.com/v1/chat/completions`。 | | ||
| | provider | 是 | String | LLM 服务的名称。可用选项:openai、deekseek、azure-openai、aimlapi、openrouter 和 openai-compatible。当选择 `aimlapi` 时,插件使用 OpenAI 兼容驱动程序,默认端点为 `https://api.aimlapi.com/v1/chat/completions`。 | |
There was a problem hiding this comment.
There is a typo in "deekseek" - it should be "deepseek" for consistency with the actual provider name used throughout the codebase.
| | instances | array[object] | True | | | LLM instance configurations. | | ||
| | instances.name | string | True | | | Name of the LLM service instance. | | ||
| | instances.provider | string | True | | [openai, deepseek, azure-openai, aimlapi, openai-compatible] | LLM service provider. When set to `openai`, the Plugin will proxy the request to `api.openai.com`. When set to `deepseek`, the Plugin will proxy the request to `api.deepseek.com`. When set to `aimlapi`, the Plugin uses the OpenAI-compatible driver and proxies the request to `api.aimlapi.com` by default. When set to `openai-compatible`, the Plugin will proxy the request to the custom endpoint configured in `override`. | | ||
| | instances.provider | string | True | | [openai, deepseek, azure-openai, aimlapi, openrouter, openai-compatible] | LLM service provider. When set to `openai`, the Plugin will proxy the request to `api.openai.com`. When set to `deepseek`, the Plugin will proxy the request to `api.deepseek.com`. When set to `aimlapi`, the Plugin uses the OpenAI-compatible driver and proxies the request to `api.aimlapi.com` by default. When set to `openrouter`, the Plugin uses the OpenAI-compatible driver and proxies the request to `openrouter.ai` by default. When set to `openai-compatible`, the Plugin will proxy the request to the custom endpoint configured in `override`. | |
There was a problem hiding this comment.
The azure-openai PR didn't add description for the option - consider adding it here? I think it does something like this
When set to
azure-openai, the plugin proxies requests to the custom endpoint configured inoverrideand additionally removes themodelparameter from user requests.
There was a problem hiding this comment.
This should be handled in a separate PR.
There was a problem hiding this comment.
(when I have time. Or I will create a issue.
| ["openai-compatible"] = openai_compatible_chat_schema, | ||
| ["azure-openai"] = openai_compatible_chat_schema | ||
| ["azure-openai"] = openai_compatible_chat_schema, | ||
| ["openrouter"] = openai_compatible_chat_schema |
There was a problem hiding this comment.
we can add , at the end of this line
| } | ||
|
|
||
| function _M.is_openai_compatible_provider(provider) | ||
| if provider == "openai" or |
There was a problem hiding this comment.
I think we can use an array object to maintain it
It is easy to maintain in this way, here is the example code:
do
local openai_compatible_list = {
"openai",
"azure_openai",
... ...
"together",
}
local openai_compatible_kv = {}
for _, provider in ipairs(openai_compatible_list) do
openai_compatible_kv[provider] = true
end
function _M.is_openai_compatible_provider(provider)
if openai_compatible_kv[provider] then
return true
end
...
end
end| "aimlapi", | ||
| "openai-compatible", | ||
| "azure-openai" | ||
| "azure-openai", |
There was a problem hiding this comment.
bzp2010
left a comment
There was a problem hiding this comment.
Code modification approved
| | ------------------------- | ------------ | -------- | ------------------------------------------------------------------------------------ | | ||
| | prompt | Yes | String | The prompt send to LLM service. | | ||
| | provider | Yes | String | Name of the LLM service. Available options: openai, deekseek, azure-openai, aimlapi and openai-compatible. When `aimlapi` is selected, the plugin uses the OpenAI-compatible driver with a default endpoint of `https://api.aimlapi.com/v1/chat/completions`. | | ||
| | provider | Yes | String | Name of the LLM service. Available options: openai, deekseek, azure-openai, aimlapi, openrouter and openai-compatible. When `aimlapi` is selected, the plugin uses the OpenAI-compatible driver with a default endpoint of `https://api.aimlapi.com/v1/chat/completions`. | |
There was a problem hiding this comment.
The provider description for ai-request-rewrite is not great - it only explained aimlapi. This should be noted and improved (maybe in a different PR?) cc: @Yilialinn

Description
Refer to the changes in #12565 to add support for openrouter
Already tested in real world:
Which issue(s) this PR fixes:
Fixes #
Checklist