feat(channel): add Baichuan type + fix max_tokens & Azure AI Foundry /openai/v1 - #6597
feat(channel): add Baichuan type + fix max_tokens & Azure AI Foundry /openai/v1#6597aiastia wants to merge 8 commits into
Conversation
Add a dedicated Baichuan (百川) channel type (type 61) instead of configuring it as a generic OpenAI-compatible channel. The Baichuan platform (https://platform.baichuan-ai.com) exposes an OpenAI-compatible /v1/chat/completions endpoint, so this change reuses the existing OpenAI relay adaptor while registering a proper channel type with its default base URL and icon. It also fixes the upstream model-list fetch for Baichuan: the GET /v1/models endpoint returns model names under data[].model instead of the OpenAI-standard data[].id, which caused "Fetch from Upstream" to return an empty list. A dedicated parser branch now handles the Baichuan response shape. Backend: - constant/channel.go: register ChannelTypeBaichuan = 61, default base URL https://api.baichuan-ai.com, and display name. - constant/api_type.go + common/api_type.go: add APITypeBaichuan and the ChannelType2APIType mapping. - relay/relay_adaptor.go: dispatch APITypeBaichuan to openai.Adaptor. - relay/common/relay_info.go: enable stream_options support. - controller/channel_upstream_update.go: parse data[].model for Baichuan. Frontend: - channels/constants.ts: add type 61 to the type map, display order, and MODEL_FETCHABLE_TYPES so the "Fetch from Upstream" button appears. - channels/lib/channel-utils.ts: map type 61 to the Baichuan icon. - i18n locales (en/zh/zh-TW/fr/ja/ru/vi): add the "Baichuan" label.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughBaichuan is added as channel type 61. Backend routing, streaming support, model discovery, and frontend metadata recognize Baichuan. Channel tests select token parameters for additional models. Azure supports newer ChangesBaichuan integration
Channel-test and Azure request handling
Container image publishing
Estimated code review effort: 3 (Moderate) | ~30 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant ChannelController
participant BaichuanAPI
participant ModelList
ChannelController->>BaichuanAPI: Request upstream models
BaichuanAPI-->>ChannelController: Return data[].model response
ChannelController->>ModelList: Normalize and return model names
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@relay/common/relay_info.go`:
- Line 351: Update openai.Adaptor.ConvertOpenAIRequest to preserve StreamOptions
for ChannelTypeBaichuan, matching its SupportStreamOptions configuration instead
of clearing the field for non-OpenAI/non-Azure channels. Add a conversion test
covering a Baichuan streaming request and verify stream_options.include_usage
remains present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: dffcd8e6-640b-4575-ab7a-9a4135a768af
📒 Files selected for processing (15)
common/api_type.goconstant/api_type.goconstant/channel.gocontroller/channel_upstream_update.gorelay/common/relay_info.gorelay/relay_adaptor.goweb/src/features/channels/constants.tsweb/src/features/channels/lib/channel-utils.tsweb/src/i18n/locales/en.jsonweb/src/i18n/locales/fr.jsonweb/src/i18n/locales/ja.jsonweb/src/i18n/locales/ru.jsonweb/src/i18n/locales/vi.jsonweb/src/i18n/locales/zh-TW.jsonweb/src/i18n/locales/zh.json
| constant.ChannelTypeSub2API: true, | ||
| constant.ChannelTypeNewAPI: true, | ||
| constant.ChannelTypeTencent: true, | ||
| constant.ChannelTypeBaichuan: true, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Expect the StreamOptions clearing logic to honor SupportStreamOptions
# or explicitly allow ChannelTypeBaichuan.
rg -n -C 8 \
'request\.StreamOptions = nil|SupportStreamOptions|ChannelTypeBaichuan' \
--glob '*.go' .Repository: QuantumNous/new-api
Length of output: 15042
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== relay_info init/StreamOptions section ==\n'
sed -n '200,245p' relay/common/relay_info.go
printf '\n== streamSupportedChannels section ==\n'
sed -n '330,355p' relay/common/relay_info.go
printf '\n== relay adaptor routing around ChannelTypeBaichuan ==\n'
sed -n '110,150p' relay/relay_adaptor.go
printf '\n== relevant OpenAI adaptor snippets ==\n'
sed -n '60,95p' relay/channel/openai/adaptor.go
sed -n '244,252p' relay/channel/openai/adaptor.go
printf '\n== channel adapter ConvertStreamOpenAIRequest references ==\n'
rg -n -C 5 'ConvertStreamOpenAIRequest|ConvertOpenAIRequest|SupportStreamOptions|StreamOptions' relay/channel --glob '*.go'Repository: QuantumNous/new-api
Length of output: 50375
Preserve stream_options through the OpenAI adaptor.
ChannelTypeBaichuan is routed to openai.Adaptor, and SupportStreamOptions is set to true, but openai.Adaptor.ConvertOpenAIRequest still clears request.StreamOptions for non-OpenAI/non-Azure channels. Baichuan streaming requests lose stream_options before the upstream call. Add ChannelTypeBaichuan to the OpenAI adaptor’s allow-list, or have ConvertOpenAIRequest preserve stream options when info.SupportStreamOptions == true. Add a conversion test that checks Baichuan streaming requests keep stream_options.include_usage.
Suggested fix in the OpenAI adaptor
- if info.ChannelType != constant.ChannelTypeOpenAI && info.ChannelType != constant.ChannelTypeAzure {
+ if !info.SupportStreamOptions &&
+ info.ChannelType != constant.ChannelTypeOpenAI &&
+ info.ChannelType != constant.ChannelTypeAzure {
request.StreamOptions = nil
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@relay/common/relay_info.go` at line 351, Update
openai.Adaptor.ConvertOpenAIRequest to preserve StreamOptions for
ChannelTypeBaichuan, matching its SupportStreamOptions configuration instead of
clearing the field for non-OpenAI/non-Azure channels. Add a conversion test
covering a Baichuan streaming request and verify stream_options.include_usage
remains present.
Source: Coding guidelines
…ax_tokens The channel test request builder hard-coded max_tokens=16 for the default chat completion probe. Azure OpenAI (and OpenAI's reasoning models) reject max_tokens and require max_completion_tokens instead, so batch-testing gpt-4o / gpt-5.x deployments on Azure returned HTTP 400: Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead. The relay path already converts max_tokens to max_completion_tokens for o-series and gpt-5-series models (relay/channel/openai/adaptor.go), but the test path only special-cased o-series and missed gpt-5-series, and did not account for Azure additionally rejecting max_tokens on the gpt-4o / gpt-4.1 family. Centralize the rule in useMaxCompletionTokens() and apply it in both the auto-detected and explicit-endpoint branches of buildTestRequest so the test request shape stays aligned with what the relay actually sends.
The Azure channel adapter always built the classic deployment-scoped URL
(/openai/deployments/{model}/{task}?api-version=...). New Azure AI
Foundry resources (endpoint host *.services.ai.azure.com, base URL ending
/openai/v1) expose the standard OpenAI path /openai/v1/chat/completions
instead, with the model passed in the request body and no api-version
query parameter. Routing these resources through the classic deployment
path returns HTTP 404 DeploymentNotFound.
Mirror the behavior already present in one-hub: when the incoming request
path starts with /v1, build /openai{path} (no api-version) instead of the
deployment-scoped URL. Classic Azure OpenAI resources keep using the
deployment path since their requests do not start with /v1.
This lets users keep the Azure channel type (and its api-key header) for
new AI Foundry resources instead of having to switch to a Custom channel.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@relay/channel/openai/adaptor.go`:
- Around line 161-167: Update the Azure URL-selection logic around the current
strings.HasPrefix(info.RequestURLPath, "/v1") branch to use an explicit
channel-configuration discriminator for Azure AI Foundry endpoints rather than
the request path alone. Exclude RelayModeRealtime from this Foundry branch
unless its deployment-specific routing is deliberately preserved, and normalize
the path by removing query parameters before rebuilding ClaudeConvertInfo.task,
requiring a strict /v1/ boundary; retain classic Azure deployment handling,
api-version propagation, and realtime routing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a4e2a864-e0b4-4e2d-a6ed-30c691cde247
📒 Files selected for processing (1)
relay/channel/openai/adaptor.go
Add a GitHub Actions workflow that builds a multi-arch (amd64 + arm64) Docker image on push to main and publishes it to GitHub Container Registry at ghcr.io/aiastia/new-api. Uses the built-in GITHUB_TOKEN for GHCR auth (packages: write), so no Docker Hub secrets are needed. This is a fork-local CI addition for self-hosting; not intended for the upstream PR branch.
Reuse the official multi-arch build matrix (native amd64 + arm64 runners, then manifest merge) with verified action SHAs. Only the registry target changes: GHCR via GITHUB_TOKEN instead of Docker Hub, image name becomes ghcr.io/<owner>/<repo>. Triggers on push to main. Drops cosign signing (not needed for fork self-hosting).
When the request path starts with /v1 (new AI Foundry resources), the previous fix prepended /openai to the full /v1/chat/completions path, yielding /openai/v1/chat/completions. That is correct only when the base URL is the bare hostname. But if the base URL already ends with /openai/v1 (as the Azure portal suggests), the final URL becomes .../openai/v1/openai/v1/chat/completions -> 404. Document the expected base URL shape (hostname only, no /openai/v1 suffix) and keep building /openai + RequestURLPath. This matches the classic Azure flow where base URL is also just the hostname.
The previous /v1-request-path check was wrong: it fired for BOTH classic
and new Azure resources, because every client reaches new-api via
/v1/chat/completions regardless of upstream type. That would have routed
classic cognitiveservices.azure.com users into the /openai/v1 branch and
broken them.
Switch the discriminator to the base URL host instead:
- *.services.ai.azure.com (AI Foundry) -> /openai/v1/... (model in body)
- everything else -> classic /openai/deployments/{model}/... path
This is the only reliable signal, and it matches how the official
adapter already special-cases cognitiveservices.azure.com above.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/docker-ghcr.yml:
- Around line 37-41: Disable persisted checkout credentials by adding
persist-credentials: false to the actions/checkout steps at
.github/workflows/docker-ghcr.yml lines 37-41 and 84-88; apply the same change
to both checkout sites.
- Around line 162-167: Restrict the “Create & push manifest (latest)” step to
runs where needs.prepare.outputs.branch equals main by adding the workflow
condition at the step level. Keep the existing manifest creation command
unchanged for main-branch runs.
- Around line 10-19: Add a workflow-level concurrency group in the Docker GHCR
workflow using the resolved build branch, so runs targeting the same branch
serialize and prevent older publications from overwriting newer main/latest
manifests. Preserve the existing push and workflow_dispatch behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4b04210c-f862-4c2a-b66e-e94b55d7596c
📒 Files selected for processing (2)
.github/workflows/docker-ghcr.ymlrelay/channel/openai/adaptor.go
🚧 Files skipped from review as they are similar to previous changes (1)
- relay/channel/openai/adaptor.go
| on: | ||
| push: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
| inputs: | ||
| branch: | ||
| description: "Branch name to build (默认 main)" | ||
| required: false | ||
| default: main | ||
| type: string |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Serialize publications of mutable tags.
Two main runs can complete out of order. The older run can then overwrite the newer main and latest manifests.
Add a workflow-level concurrency group that uses the resolved build branch.
Proposed fix
on:
push:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: "Branch name to build (默认 main)"
required: false
default: main
type: string
+concurrency:
+ group: ghcr-${{ github.repository }}-${{ inputs.branch || github.ref_name }}
+ cancel-in-progress: true
+
env:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| branch: | |
| description: "Branch name to build (默认 main)" | |
| required: false | |
| default: main | |
| type: string | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| branch: | |
| description: "Branch name to build (默认 main)" | |
| required: false | |
| default: main | |
| type: string | |
| concurrency: | |
| group: ghcr-${{ github.repository }}-${{ inputs.branch || github.ref_name }} | |
| cancel-in-progress: true | |
| env: |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/docker-ghcr.yml around lines 10 - 19, Add a workflow-level
concurrency group in the Docker GHCR workflow using the resolved build branch,
so runs targeting the same branch serialize and prevent older publications from
overwriting newer main/latest manifests. Preserve the existing push and
workflow_dispatch behavior.
| - name: Check out branch | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | ||
| with: | ||
| fetch-depth: 1 | ||
| ref: ${{ inputs.branch || github.ref }} |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Disable persisted checkout credentials.
actions/checkout persists its token in the workspace by default. The build job later supplies that workspace as the Docker build context. Disable credential persistence because the shown commands do not need Git authentication after checkout.
.github/workflows/docker-ghcr.yml#L37-L41: addpersist-credentials: false..github/workflows/docker-ghcr.yml#L84-L88: addpersist-credentials: false.
🧰 Tools
🪛 zizmor (1.28.0)
[warning] 37-41: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
📍 Affects 1 file
.github/workflows/docker-ghcr.yml#L37-L41(this comment).github/workflows/docker-ghcr.yml#L84-L88
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/docker-ghcr.yml around lines 37 - 41, Disable persisted
checkout credentials by adding persist-credentials: false to the
actions/checkout steps at .github/workflows/docker-ghcr.yml lines 37-41 and
84-88; apply the same change to both checkout sites.
Source: Linters/SAST tools
| - name: Create & push manifest (latest) | ||
| run: | | ||
| docker buildx imagetools create \ | ||
| -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ | ||
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \ | ||
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64 |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Publish latest only from main.
A manual run can select a non-main branch. This step still overwrites :latest with that branch image.
Add a condition that permits this manifest only when needs.prepare.outputs.branch is main.
Proposed fix
- name: Create & push manifest (latest)
+ if: needs.prepare.outputs.branch == 'main'
run: |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Create & push manifest (latest) | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64 | |
| - name: Create & push manifest (latest) | |
| if: needs.prepare.outputs.branch == 'main' | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64 |
🧰 Tools
🪛 zizmor (1.28.0)
[warning] 165-165: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[warning] 166-166: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[info] 166-166: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[warning] 167-167: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[info] 167-167: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/docker-ghcr.yml around lines 162 - 167, Restrict the
“Create & push manifest (latest)” step to runs where
needs.prepare.outputs.branch equals main by adding the workflow condition at the
step level. Keep the existing manifest creation command unchanged for
main-branch runs.
Instead of hard-coding host detection (services.ai.azure.com), let the user signal the new AI Foundry endpoint by including /openai at the end of the base URL. This mirrors how the Azure portal presents the endpoint (https://xxx.services.ai.azure.com/openai) and avoids fragile host matching. - base URL ending in /openai -> append /v1/chat/completions (AI Foundry) - base URL without /openai -> classic /openai/deployments/{model}/... path Trim trailing slash so "host/openai/" and "host/openai" both work.
本 PR 包含三个独立改动,合并提交以便一并审阅。可按需拆分(三个 commit 相互独立)。
📝 变更描述 / Description
1. 新增百川(Baichuan)渠道类型
为百川平台(https://platform.baichuan-ai.com)新增独立渠道类型(`ChannelTypeBaichuan = 61
)。百川提供 OpenAI 兼容的/v1/chat/completions端点,复用现有openai.Adaptor,仅注册类型与默认 base URL。同时修复其「获取上游模型」:GET /v1/models用data[].model而非标准data[].id`,新增专门分支解析。2. 修复渠道测试对
max_tokens的处理渠道测试请求
buildTestRequest硬编码max_tokens=16。Azure OpenAI 与 OpenAI reasoning 模型要求max_completion_tokens,导致 Azure 上批量测试gpt-4o/gpt-5.x返回 400。转发链路已对 o 系列/gpt-5 系列转换,但测试路径只特判 o 系列,且未考虑 Azure 对gpt-4o/gpt-4.1也拒绝max_tokens。将规则集中到useMaxCompletionTokens(),在两个分支统一应用。3. 支持新版 Azure AI Foundry
/openai/v1端点Azure 渠道适配器总是构建经典 deployment 路径(
/openai/deployments/{model}/{task}?api-version=)。新版 Azure AI Foundry 资源(host*.services.ai.azure.com,base URL 含/openai/v1)使用标准 OpenAI 路径/openai/v1/chat/completions,模型名放请求体,不带 api-version。新版资源走经典路径会返回 404 DeploymentNotFound。参照 one-hub 已有逻辑:当请求路径以
/v1开头时,构建/openai{path}(无 api-version),否则走经典 deployment 路径。经典 Azure OpenAI 资源的请求路径不以/v1开头,行为不变。这让用户对 AI Foundry 资源可继续用 Azure 渠道类型(及其api-key头),不必改用 Custom 渠道。🚀 变更类型 / Type of change
🔗 关联任务 / Related Issue
✅ 提交前检查项 / Checklist
go build ./...编译通过(golang:1.25 容器内 exit 0)。📸 运行证明 / Proof of Work
后端编译:
百川 /v1/models 返回格式(改动 1 修复的解析问题):
{"data":[{"model":"Baichuan-M3",...},{"model":"Baichuan4-Turbo",...}]}Azure 批量测试对比(改动 2,实测):
Azure AI Foundry 端点(改动 3):
*.services.ai.azure.com)选 Azure 类型 → 强制走/openai/deployments/{model}/→ 404/v1开头时走/openai/v1/chat/completions→ 正常工作Summary by CodeRabbit
New Features
Bug Fixes